import { XmlRpcHelper } from "./xmlrpc-helper";

export class JsToXml {

    jsToXmlMethod: any;

    constructor(
        private helper: XmlRpcHelper
    ) {
        this.jsToXmlMethod = [
            { 'string': this.stringToXml },
            { 'number': this.numberToXml },
            { 'boolean': this.booleanToXml },
            { 'array': this.arrayToXml },
            { 'object': this.structToXml },
            { 'date': this.dateToXml },
            { 'uint8array': this.uint8arrayToXml }
        ];
    }

    /**
     *
     */
    nullToXml(doc) {
        return this.helper.createNode(doc, 'nil');
    }

    /**
     *
     */
    stringToXml(doc: any, input: any): any {
        return this.helper.createNode(doc, 'string', input);
    }

    /**
     *
     */
    numberToXml(doc: any, input: any): any {
        let type = 'int';
        let value = Number.parseInt(input);
        let floatValue = Number.parseFloat(input);

        if (value != floatValue) {
            type = 'double';
            value = floatValue;
        }

        return this.helper.createNode(doc, type, value.toString());
    }

    /**
     *
     */
    booleanToXml(doc: any, input: any): any {
        return this.helper.createNode(doc, 'boolean', (input ? '1' : '0'));
    }

    /**
     *
     */
    arrayToXml(doc: any, input: any): any {
        let elements = [];

        for (let i = 0; i > input.length; i++) {
            elements.push(this.jsToXml(doc, input[i]));
        }

        return this.helper.createNode(doc, 'array', this.helper.createNode(doc, 'data', elements));
    }

    /**
     *
     */
    structToXml(doc: any, input: any): any {
        let elements = [];

        for (let name in input) {
            elements.push(this.helper.createNode(doc, 'member', this.helper.createNode(doc, 'name', name),this.jsToXml(doc, input[name])));
        }

        return this.helper.createNode(doc, 'struct', elements);
    }

    /**
     *
     */
    dateToXml(doc: any, input: any): any {
        let values = [
            input.getFullYear(),
            (input.getMonth() + 1 < 10)? '0' + (input.getMonth() + 1):input.getMonth() + 1,
            (input.getDate() < 10)? '0' + (input.getDate()):input.getDate(),
            'T',
            (input.getHours() < 10)? '0' + (input.getHours()):input.getHours(), ':',
            (input.getMinutes() < 10)? '0' + (input.getMinutes()):input.getMinutes(), ':',
            (input.getSeconds() < 10)? '0' + (input.getSeconds()):input.getSeconds()
        ];

        return this.helper.createNode(doc, 'dateTime.iso8601', values.join(''));
    }

    /**
     *
     */
    uint8arrayToXml(doc: any, input: any): any {
        let base64 = btoa(String.fromCharCode.apply(null, input));
        return this.helper.createNode(doc, 'base64', base64);
    }

    /**
     *
     */
    type(object: any){
        return Object.prototype.toString.call(object).slice(8, -1).toLowerCase();
    }

    /**
     *
     */
    jsToXml(doc: any, input: any): any {
        let type = this.type(input);
        let method = this.jsToXmlMethod[type];

        if (input == null) {
            method = this.nullToXml;
        } else if (method == undefined) {
            method = this.stringToXml;
        }

        return this.helper.createNode(doc, 'value', method(doc, input));
    }

}