const generation = require("./Generator");
const assist = require('./assist');

const java = require('java');

/**
 *  ComplexBarcodeGenerator for backend complex barcode (e.g. SwissQR) images generation.
 *
 *  This sample shows how to create and save a SwissQR image.
 *    let swissQRCodetext = new SwissQRCodetext(null);
 *    swissQRCodetext.getBill().setAccount("Account");
 *    swissQRCodetext.getBill().setBillInformation("BillInformation");
 *    swissQRCodetext.getBill().setBillInformation("BillInformation");
 *    swissQRCodetext.getBill().setAmount(1024);
 *    swissQRCodetext.getBill().getCreditor().setName("Creditor.Name");
 *    swissQRCodetext.getBill().getCreditor().setAddressLine1("Creditor.AddressLine1");
 *    swissQRCodetext.getBill().getCreditor().setAddressLine2("Creditor.AddressLine2");
 *    swissQRCodetext.getBill().getCreditor().setCountryCode("Nl");
 *    swissQRCodetext.getBill().setUnstructuredMessage("UnstructuredMessage");
 *    swissQRCodetext.getBill().setReference("Reference");
 *    swissQRCodetext.getBill().addalternativeScheme(new AlternativeScheme("AlternativeSchemeInstruction1"));
 *    swissQRCodetext.getBill().addalternativeScheme(new AlternativeScheme("AlternativeSchemeInstruction2"));
 *    swissQRCodetext.getBill().setDebtor(new Address(null));
 *    swissQRCodetext.getBill().getDebtor().setName("Debtor.Name");
 *    swissQRCodetext.getBill().getDebtor().setAddressLine1("Debtor.AddressLine1");
 *    swissQRCodetext.getBill().getDebtor().setAddressLine2("Debtor.AddressLine2");
 *    swissQRCodetext.getBill().getDebtor().setCountryCode("Lux");
 *    let cg = new ComplexBarcodeGenerator(swissQRCodetext);
 *    let res = cg.generateBarCodeImage();
 */
class ComplexBarcodeGenerator extends assist.BaseJavaClass {
    static javaClassName = "com.aspose.mw.barcode.complexbarcode.MwComplexBarcodeGenerator";
    parameters;

    init() {
        this.parameters = new generation.BaseGenerationParameters(this.getJavaClass().getParametersSync());
    }

    /**
     * Generation parameters.
     */
    getParameters() {
        return this.parameters;
    }

    /**
     * Creates an instance of ComplexBarcodeGenerator.
     * @param arg Complex codetext
     */
    constructor(arg) {
        super(ComplexBarcodeGenerator.initComplexBarcodeGenerator(arg));
        this.init();
    }

    static initComplexBarcodeGenerator(arg) {
        if (arg instanceof SwissQRCodetext) {
            let javaComplexBarcodeGenerator = java.import(ComplexBarcodeGenerator.javaClassName);
            return new javaComplexBarcodeGenerator(arg.getJavaClass())
        } else {
            let java_link = java.import(arg);
            return new java_link();
        }
    }

    generateBarcodeImage() {
        let base64Image = this.getJavaClass().generateBarCodeImageSync();
        return (base64Image);
    }

    save(filePath) {
        let image = this.generateBarcodeImage();
        file_put_contents(filePath, image);
    }

    saveImageFormat(filePath, format_name) {
        let image = this.generateBarcodeImage(format_name);
        file_put_contents(filePath, image);
    }
}

/**
 * Address of creditor or debtor.
 *
 * You can either set street, house number, postal code and town (type structured address)
 * or address line 1 and 2 (type combined address elements). The type is automatically set
 * once any of these fields is set. Before setting the fields, the address type is undetermined.
 * If fields of both types are set, the address type becomes conflicting.
 * Name and country code must always be set unless all fields are empty.
 */
class Address extends assist.BaseJavaClass {
    static javaClassName = "com.aspose.mw.barcode.complexbarcode.MwAddress";

    constructor(arg) {
        super(Address.initAddress(arg));
        this.init();
    }

    static initAddress(arg) {
        if (arg == null) {
            let javaAddress = java.import(Address.javaClassName);
            return new javaAddress();
        }
        return arg;
    }

    /**
     * Gets the address type.
     *
     * The address type is automatically set by either setting street / house number
     * or address line 1 and 2. Before setting the fields, the address type is Undetermined.
     * If fields of both types are set, the address type becomes Conflicting.
     *
     * Value: The address type.
     */
    getType() {
        return this.getJavaClass().getTypeSync();
    }

    /**
     * Gets the name, either the first and last name of a natural person or the
     * company name of a legal person.
     * Value: The name.
     */
    getName() {
        return this.getJavaClass().getNameSync();
    }

    /**
     * Sets the name, either the first and last name of a natural person or the
     * company name of a legal person.
     * Value: The name.
     */
    setName(value) {
        this.getJavaClass().setNameSync(value);
    }

    /**
     * Gets the address line 1.
     *
     * Address line 1 contains street name, house number or P.O. box.
     *
     * Setting this field sets the address type to AddressType.COMBINED_ELEMENTS unless it's already
     * AddressType.STRUCTURED, in which case it becomes AddressType.CONFLICTING.
     *
     * This field is only used for combined elements addresses and is optional.
     *
     * Value: The address line 1.
     */
    getAddressLine1() {
        return this.getJavaClass().getAddressLine1Sync();
    }

    /**
     * Sets the address line 1.
     *
     * Address line 1 contains street name, house number or P.O. box.
     *
     * Setting this field sets the address type to AddressType.COMBINED_ELEMENTS unless it's already
     * AddressType.STRUCTURED, in which case it becomes AddressType.CONFLICTING.
     *
     * This field is only used for combined elements addresses and is optional.
     *
     * Value: The address line 1.
     */
    setAddressLine1(value) {
        this.getJavaClass().setAddressLine1Sync(value);
    }

    /**
     * Gets the address line 2.
     * Address line 2 contains postal code and town.
     * Setting this field sets the address type to AddressType.COMBINED_ELEMENTS unless it's already
     * AddressType.STRUCTURED, in which case it becomes AddressType.CONFLICTING.
     * This field is only used for combined elements addresses. For this type, it's mandatory.
     * Value: The address line 2.
     */
    getAddressLine2() {
        return this.getJavaClass().getAddressLine2Sync();
    }

    /**
     * Sets the address line 2.
     * Address line 2 contains postal code and town.
     * Setting this field sets the address type to AddressType.COMBINED_ELEMENTS unless it's already
     * AddressType.STRUCTURED, in which case it becomes AddressType.CONFLICTING.
     * This field is only used for combined elements addresses. For this type, it's mandatory.
     * Value: The address line 2.
     */
    setAddressLine2(value) {
        this.getJavaClass().setAddressLine2Sync(value);
    }

    /**
     * Gets the street.
     * The street must be speicfied without house number.
     * Setting this field sets the address type to AddressType.STRUCTURED unless it's already
     * AddressType.COMBINED_ELEMENTS, in which case it becomes AddressType.CONFLICTING.
     * This field is only used for structured addresses and is optional.
     * Value: The street.
     */
    getStreet() {
        return this.getJavaClass().getStreetSync();
    }

    /**
     * Sets the street.
     *
     * The street must be speicfied without house number.
     *
     * Setting this field sets the address type to AddressType.STRUCTURED unless it's already
     * AddressType.COMBINED_ELEMENTS, in which case it becomes AddressType.CONFLICTING.
     *
     * This field is only used for structured addresses and is optional.
     *
     * Value: The street.
     */
    setStreet(value) {
        this.getJavaClass().setStreetSync(value);
    }

    /**
     * Gets the house number.
     *
     * Setting this field sets the address type to AddressType.STRUCTURED unless it's already
     * AddressType.COMBINED_ELEMENTS, in which case it becomes AddressType.CONFLICTING.
     *
     * This field is only used for structured addresses and is optional.
     *
     * Value: The house number.
     */
    getHouseNo() {
        return this.getJavaClass().getHouseNoSync();
    }

    /**
     * Sets the house number.
     *
     * Setting this field sets the address type to AddressType.STRUCTURED unless it's already
     * AddressType.COMBINED_ELEMENTS, in which case it becomes AddressType.CONFLICTING.
     *
     * This field is only used for structured addresses and is optional.
     *
     * Value: The house number.
     */
    setHouseNo(value) {
        this.getJavaClass().setHouseNoSync(value);
    }

    /**
     * Gets the postal code.
     *
     * Setting this field sets the address type to AddressType.STRUCTURED unless it's already
     * AddressType.COMBINED_ELEMENTS, in which case it becomes AddressType.CONFLICTING.
     *
     * This field is only used for structured addresses. For this type, it's mandatory.
     *
     * Value: The postal code.
     */
    getPostalCode() {
        return this.getJavaClass().getPostalCodeSync();
    }

    /**
     * Sets the postal code.
     *
     * Setting this field sets the address type to AddressType.STRUCTURED unless it's already
     * AddressType.COMBINED_ELEMENTS, in which case it becomes AddressType.CONFLICTING.
     *
     * This field is only used for structured addresses. For this type, it's mandatory.
     *
     * Value: The postal code.
     */
    setPostalCode(value) {
        this.getJavaClass().setPostalCodeSync(value);
    }

    /**
     * Gets the town or city.
     *
     * Setting this field sets the address type to AddressType.STRUCTURED unless it's already
     * AddressType.COMBINED_ELEMENTS, in which case it becomes AddressType.CONFLICTING.
     *
     * This field is only used for structured addresses. For this type, it's mandatory.
     *
     * Value: The town or city.
     */
    getTown() {
        return this.getJavaClass().getTownSync();
    }

    /**
     * Sets the town or city.
     *
     * Setting this field sets the address type to AddressType.STRUCTURED unless it's already
     * AddressType.COMBINED_ELEMENTS, in which case it becomes AddressType.CONFLICTING.
     *
     * This field is only used for structured addresses. For this type, it's mandatory.
     *
     * Value: The town or city.
     */
    setTown(value) {
        this.getJavaClass().setTownSync(value);
    }

    /**
     * Gets the two-letter ISO country code.
     *
     * The country code is mandatory unless the entire address contains null or emtpy values.
     *
     * Value: The ISO country code.
     */
    getCountryCode() {
        return this.getJavaClass().getCountryCodeSync();
    }

    /**
     * Sets the two-letter ISO country code.
     *
     * The country code is mandatory unless the entire address contains null or emtpy values.
     *
     * Value: The ISO country code.
     */
    setCountryCode(value) {
        this.getJavaClass().setCountryCodeSync(value);
    }

    /**
     * Clears all fields and sets the type to AddressType.UNDETERMINED.
     */
    clear() {
        this.setName(null);
        this.setAddressLine1(null);
        this.setaddressLine2(null);
        this.setStreet(null);
        this.setHouseNo(null);
        this.setPostalCode(null);
        this.setTown(null);
        this.setCountryCode(null);
    }

    /**
     * Determines whether the specified object is equal to the current object.
     * @return true if the specified object is equal to the current object; otherwise, false.
     * @param obj The object to compare with the current object.
     */
    equals(obj) {
        return this.getJavaClass().equalsSync(obj);
    }

    /**
     * Gets the hash code for this instance.
     * @return A hash code for the current object.
     */
    hashCode() {
        return this.getJavaClass().hashCodeSync();
    }

    init() {
        // TODO: Implement init() method.
    }
}

/**
 * Address type
 */
AddressType =
    {
        /**
         * Undetermined
         */
        UNDETERMINED: "0",
        /**
         * Structured address
         */
        STRUCTURED: "1",
        /**
         * Combined address elements
         */
        COMBINED_ELEMENTS: "2",
        /**
         * Conflicting
         */
        CONFLICTING: "3"
    };

/**
 * Alternative payment scheme instructions
 */
class AlternativeScheme extends assist.BaseJavaClass {
    static get javaClassName() {
        return "com.aspose.mw.barcode.complexbarcode.MwAlternativeScheme";
    }

    constructor(instruction)
    {
        let javaAlternativeScheme = java.import(AlternativeScheme.javaClassName);
        super(new javaAlternativeScheme(instruction));
    }

    /**
     * Gets the payment instruction for a given bill.
     *
     * The instruction consists of a two letter abbreviation for the scheme, a separator characters
     * and a sequence of parameters(separated by the character at index 2).
     *
     * Value: The payment instruction.
     */
    getInstruction() {
        return this.getJavaClass().getInstructionSync();
    }

    /**
     * Gets the payment instruction for a given bill.
     * The instruction consists of a two letter abbreviation for the scheme, a separator characters
     * and a sequence of parameters(separated by the character at index 2).
     * Value: The payment instruction.
     */
    setInstruction(value) {
        this.getJavaClass().setInstructionSync(value);
    }

    /**
     * Determines whether the specified object is equal to the current object.
     * @return true if the specified object is equal to the current object; otherwise, false.
     * @param obj The object to compare with the current object.
     */
    equals(obj) {
        return this.getJavaClass().equalsSync(obj);
    }

    /**
     * Gets the hash code for this instance.
     * @return  hash code for the current object.
     */
    hashCode() {
        return this.getJavaClass().hashCodeSync();
    }

    init() {
        // TODO: Implement init() method.
    }
}

/**
 *  ComplexCodetextReader decodes codetext to specified complex barcode type.
 *
 *  This sample shows how to recognize and decode SwissQR image.
 *
 *  let cr = new BarCodeReader("SwissQRCodetext.png", DecodeType.QR);
 *  cr.read();
 *  let result = ComplexCodetextReader.tryDecodeSwissQR(cr.getCodeText(false));
 */
class ComplexCodetextReader {
    static javaClassName = "com.aspose.mw.barcode.complexbarcode.MwComplexCodetextReader";

    /**
     * Decodes SwissQR codetext.
     *
     * @return decoded SwissQRCodetext or null.
     * @param encodedCodetext encoded codetext
     */
    static tryDecodeSwissQR(encodedCodetext) {
        let javaPhpComplexCodetextReader = java.import(ComplexCodetextReader.javaClassName);
        return new SwissQRCodetext(javaPhpComplexCodetextReader.tryDecodeSwissQRSync(encodedCodetext));
    }
}

/**
 * SwissQR bill standard version
 */
QrBillStandardVersion =
    {
        /**
         *
         * Version 2.0
         *
         */
        V2_0: "0"
    };

/**
 * SwissQR bill data
 */
class SwissQRBill extends assist.BaseJavaClass {
    creditor;
    debtor;
    alternativeSchemes;

    init() {
        this.creditor = new Address(this.getJavaClass().getCreditorSync());
        this.debtor = new Address(this.getJavaClass().getDebtorSync());
        this.alternativeSchemes = SwissQRBill.convertAlternativeSchemes(this.getJavaClass().getAlternativeSchemesSync());
        // TODO: Implement init() method.
    }

    constructor(javaClass) {
        super(javaClass);
        this.init();
    }

    static convertAlternativeSchemes(javaAlternativeSchemes) {
        let alternativeSchemes = [];
        for (let i = 0; i < javaAlternativeSchemes.size(); i++) {
            alternativeSchemes[i] = new AlternativeScheme(javaAlternativeSchemes.get(i));
        }
        return alternativeSchemes;
    }

    /**
     * Gets the version of the SwissQR bill standard.
     * Value: The SwissQR bill standard version.
     */
    getVersion() {
        return this.getJavaClass().getVersionSync();
    }

    /**
     * Sets the version of the SwissQR bill standard.
     * Value: The SwissQR bill standard version.
     */
    setVersion(value) {
        this.getJavaClass().setVersionSync(value);
    }

    /**
     * Gets the payment amount.
     *
     * Valid values are between 0.01 and 999,999,999.99.
     *
     * Value: The payment amount.
     */
    getAmount() {
        return this.getJavaClass().getAmountSync();
    }

    /**
     * Sets the payment amount.
     *
     * Valid values are between 0.01 and 999,999,999.99.
     *
     * Value: The payment amount.
     */
    setAmount(value) {
        this.getJavaClass().setAmountSync(value);
    }

    /**
     * Gets the payment currency.
     *
     * Valid values are "CHF" and "EUR".
     *
     * Value: The payment currency.
     */
    getCurrency() {
        return this.getJavaClass().getCurrencySync();
    }

    /**
     * Sets the payment currency.
     *
     * Valid values are "CHF" and "EUR".
     *
     * Value: The payment currency.
     */
    setCurrency(value) {
        this.getJavaClass().setCurrencySync(value);
    }

    /**
     * Gets the creditor's account number.
     *
     * Account numbers must be valid IBANs of a bank of Switzerland or
     * Liechtenstein. Spaces are allowed in the account number.
     *
     * Value: The creditor account number.
     */
    getAccount() {
        return this.getJavaClass().getAccountSync();
    }

    /**
     * Sets the creditor's account number.
     *
     * Account numbers must be valid IBANs of a bank of Switzerland or
     * Liechtenstein. Spaces are allowed in the account number.
     *
     * Value: The creditor account number.
     */
    setAccount(value) {
        this.getJavaClass().setAccountSync(value);
    }

    /**
     * Gets the creditor address.
     * Value: The creditor address.
     */
    getCreditor() {
        return this.creditor;
    }

    /**
     * Sets the creditor address.
     * Value: The creditor address.
     */
    setCreditor(value) {
        this.creditor = value;
        this.getJavaClass().setCreditor(value.getJavaClassSync());
    }

    /**
     * Gets the creditor payment reference.
     *
     * The reference is mandatory for SwissQR IBANs, i.e.IBANs in the range
     * CHxx30000xxxxxx through CHxx31999xxxxx.
     *
     * If specified, the reference must be either a valid SwissQR reference
     * (corresponding to ISR reference form) or a valid creditor reference
     * according to ISO 11649 ("RFxxxx"). Both may contain spaces for formatting.
     *
     * Value: The creditor payment reference.
     */
    getReference() {
        return this.getJavaClass().getReferenceSync();
    }

    /**
     * Sets the creditor payment reference.
     *
     * The reference is mandatory for SwissQR IBANs, i.e.IBANs in the range
     * CHxx30000xxxxxx through CHxx31999xxxxx.
     *
     * If specified, the reference must be either a valid SwissQR reference
     * (corresponding to ISR reference form) or a valid creditor reference
     * according to ISO 11649 ("RFxxxx"). Both may contain spaces for formatting.
     *
     * Value: The creditor payment reference.
     */
    setReference(value) {
        this.getJavaClass().setReferenceSync(value);
    }

    /**
     * Creates and sets a ISO11649 creditor reference from a raw string by prefixing
     * the String with "RF" and the modulo 97 checksum.
     *
     * Whitespace is removed from the reference
     *
     * @exception ArgumentException rawReference contains invalid characters.
     * @param rawReference The raw reference.
     */
    createAndSetCreditorReference(rawReference) {
        this.getJavaClass().createAndSetCreditorReferenceSync(rawReference);
    }

    /**
     * Gets the debtor address.
     *
     * The debtor is optional. If it is omitted, both setting this field to
     * null or setting an address with all null or empty values is ok.
     *
     * Value: The debtor address.
     */
    getDebtor() {
        return this.creditor;
    }

    /**
     * Sets the debtor address.
     *
     * The debtor is optional. If it is omitted, both setting this field to
     * null or setting an address with all null or empty values is ok.
     *
     * Value: The debtor address.
     */
    setDebtor(value) {
        this.debtor = value;
        this.getJavaClass().setDebtor(value.getJavaClass());
    }

    /**
     * Gets the additional unstructured message.
     * Value: The unstructured message.
     */
    getUnstructuredMessage() {
        return this.getJavaClass().getUnstructuredMessageSync();
    }

    /**
     * Sets the additional unstructured message.
     * Value: The unstructured message.
     */
    setUnstructuredMessage(value) {
        this.getJavaClass().setUnstructuredMessageSync(value);
    }

    /**
     * Gets the additional structured bill information.
     * Value: The structured bill information.
     */
    getBillInformation() {
        return this.getJavaClass().getBillInformationSync();
    }

    /**
     * Sets the additional structured bill information.
     * Value: The structured bill information.
     */
    setBillInformation(value) {
        this.getJavaClass().setBillInformationSync(value);
    }

    /**
     * Gets ors sets the alternative payment schemes.
     *
     * A maximum of two schemes with parameters are allowed.
     *
     * Value: The alternative payment schemes.
     */
    getAlternativeSchemes() {
        return this.alternativeSchemes;
    }

    /**
     * Gets or sets the alternative payment schemes.
     *
     * A maximum of two schemes with parameters are allowed.
     *
     * Value: The alternative payment schemes.
     */
    setAlternativeSchemes(value) {
        this.getJavaClass().getAlternativeSchemesSync().clearSync();
        for (let i = 0; i < sizeof(value); i++) {
            this.getJavaClass().getAlternativeSchemesSync().setSync(value[i].getJavaClass());
        }
    }

    /**
     * Add the alternative payment schemes.
     */
    addAlternativeScheme(value) {
        let alternativeScheme = this.getJavaClass().getAlternativeSchemesSync().addSync(value.getJavaClass());
    }

    /**
     * Determines whether the specified object is equal to the current object.
     * @return true if the specified object is equal to the current object; otherwise, false.
     * @param obj The object to compare with the current object.
     */
    equals(obj) {
        return this.getJavaClass().equalsSync(obj.getJavaClass());
    }

    /**
     * Gets the hash code for this instance.
     * @return A hash code for the current object.
     */
    hashCode() {
        return this.getJavaClass().hashCodeSync();
    }
}

/**
 * Class for encoding and decoding the text embedded in the SwissQR code.
 */
class SwissQRCodetext extends assist.BaseJavaClass {
    static javaClassName = "com.aspose.mw.barcode.complexbarcode.MwSwissQRCodetext";
    bill;

    init() {
        this.bill = new SwissQRBill(this.getJavaClass().getBillSync());
    }

    /**
     * SwissQR bill data
     */
    getBill() {
        return this.bill;
    }

    /**
     * Creates an instance of SwissQRCodetext.
     *
     * @param bill SwissQR bill data
     * @throws BarcodeException
     */
    constructor(arg) {
        super(SwissQRCodetext.initSwissQRCodetext(arg));
        this.init();
    }

    static initSwissQRCodetext(arg) {
        if (arg instanceof SwissQRBill) {
            let javaSwissQRCodetext = java.import(SwissQRCodetext.javaClassName);
            return new javaSwissQRCodetext(arg.getJavaClass());
        } else if (arg == null) {
            let javaSwissQRCodetext = java.import(SwissQRCodetext.javaClassName);
            return new javaSwissQRCodetext();
        } else {
            return arg;
        }
    }

    /**
     * Construct codetext from SwissQR bill data
     *
     * @return Constructed codetext
     */
    getConstructedCodetext() {
        return this.getJavaClass().getConstructedCodetextSync();
    }

    /**
     * Initializes Bill with constructed codetext.
     *
     * @param constructedCodetext Constructed codetext.
     */
    initFromString(constructedCodetext) {
        this.getJavaClass().initFromString(constructedCodetext);
    }

    /**
     * Gets barcode type.
     *
     * @return Barcode type.
     */
    getBarcodeType() {
        return this.getJavaClass().getBarcodeTypeSync();
    }
}

module.exports = {
    SwissQRCodetext, ComplexBarcodeGenerator,ComplexCodetextReader,AlternativeScheme,Address
};