namespace ti_common {

    let fs = require('fs');
	let path = require('path');
	let os = require('os');
	const logFileLoc = path.join(os.tmpdir(), 'ti_cloud_storage', 'uniflash');
    // configure desktop dinfra
    let dinfraCommon = require(path.resolve('../ticloudagent/server/common/dinfra_common.js'));
    dinfraCommon.setDinfra(require(path.resolve('../dinfra-library/desktop/dinfra.js')));
    let dinfra = dinfraCommon.dinfra;
    let logger = dinfra.logger('uniflash');
    dinfra.dlog.console();

    let dconfig = {
        'origin': {
            'landscape': 'localhost',
            'cluster': 'none',
            'instance': 'localhost'
		},
		'logging': {
            'base-path': logFileLoc,
            'format': {
                'render': 'condensed'
            }
        },
        'databases': {
            'defaults': {
                'type': 'file',
                'path': '../deskdb'
            }
        },
        'paths': {

        }
    };

    let dinfraConfigue = dinfra.configure(dconfig);

    let queryConfigImpl = require(path.resolve('../ticloudagent/server/server_apis/query_config.js'));
    let getConfigInfoImpl = require(path.resolve('../ticloudagent/server/server_apis/get_config_info.js'));
    let getSupportingFilesImpl = require(path.resolve('../ticloudagent/server/server_apis/get_supporting_files.js'));
    let generateConfigImpl = require(path.resolve('../ticloudagent/server/server_apis/generate_config.js'));
    let getFileImpl = require(path.resolve('../ticloudagent/server/server_apis/get_file.js'));
    let getComponentInfoImpl = require(path.resolve('../ticloudagent/server/server_apis/get_component_info.js'));
    let WriteStream = require(path.resolve('../uniflash/public/ti_common/nw/streams.js')).write;
    let ReadStream = require(path.resolve('../uniflash/public/ti_common/nw/streams.js')).read;

    interface ResAPICallBack {
        (res: any): void;
    };

    class NWAgentAPI implements IAgentAPI {

        static $inject = ['$q', '$log'];

        constructor(private $q, private $log) {
            dinfraConfigue
                .then(() => {
                    this.$log.log('NWAgentAPI: dinfraConfigue resolved successfully.');
                })
                .catch((err) => {
                    this.$log.error(err);
                })
                .done();
        }

        getLpListJson(): angular.IPromise<any> {
            let deferred = this.$q.defer();
            let jsonPath = path.resolve('../uniflash/public/target_setup/data/lpList.json');
            let jsonData = JSON.stringify(require(jsonPath));
            let retObj = { data: jsonData };
            deferred.resolve(retObj);
            return deferred.promise;
        }

        private uint8ToString(buf, resolve) {
            let blob = new Blob([buf]);
            let f = new FileReader();
            f.onload = function () {
                resolve({
                    data: this.result
                });
            };
            f.readAsText(blob);
        }

        //text 
        getConfigInfo(OS: any): angular.IPromise<any> {
            let params = { os: OS };

            return this.$q((resolve, reject) => {
                dinfraConfigue
                    .then(() => {
                        let res = new WriteStream();
                        getConfigInfoImpl(params, res);
                        res.on('finish', () => {
                            this.uint8ToString(res.getData(), resolve);
                        });
                        res.on('error', reject);
                    });
            });
        }

        //text
        getSupportingFiles(ccxmlFileContents: string, OS: string, osBits?: number): angular.IPromise<any> {
            let params = { os: OS, bitSize: osBits };
            return this.$q((resolve, reject) => {
                dinfraConfigue
                    .then(() => {
                        let req = new ReadStream(ccxmlFileContents);
                        let res = new WriteStream();
                        getSupportingFilesImpl(params, req, res);
                        res.on('finish', () => {
                            this.uint8ToString(res.getData(), resolve);
                        });
                        res.on('error', reject);
                        req.on('error', reject);
                    });
            });
        }

        //text
        queryConfig(ccxmlFileContents: string, OS: string): angular.IPromise<any> {
            return this.$q((resolve, reject) => {
                dinfraConfigue
                    .then(() => {
                        let req = new ReadStream(ccxmlFileContents);
                        let res = new WriteStream();
                        queryConfigImpl({ os: OS }, req, res);
                        res.on('finish', () => {
                            this.uint8ToString(res.getData(), resolve);
                        });
                        res.on('error', reject);
                        req.on('error', reject);
                    });
            });
        }

        getConfigurables(OS: string, connectionID: string, deviceID: string): angular.IPromise<string> {
            return this.$q((resolve, reject) => {
                dinfraConfigue
                    .then(() => {
                        let res = new WriteStream();
                        generateConfigImpl.getConfigurables(connectionID, deviceID, OS, res);
                        res.on('finish', () => {
                            this.uint8ToString(res.getData(), resolve);
                        });
                        res.on('error', reject);
                    });
            });
        }


        //text
        getConfig(OS: string, connectionID: string, deviceID: string, configurablesJson?: string): angular.IPromise<string> {
            return this.$q((resolve, reject) => {
                dinfraConfigue
                    .then(() => {
                        let res = new WriteStream();
                        if (configurablesJson) {
                            let params = {
                                os: OS,
                                connectionID: connectionID,
                                deviceID: deviceID
                            };
                            let req = new ReadStream(configurablesJson);
                            generateConfigImpl.advanced(params, req, res);
                        } else {
                            generateConfigImpl.default(connectionID, deviceID, OS, res);
                        }
                        res.on('finish', () => {
                            this.uint8ToString(res.getData(), resolve);
                        });
                        res.on('error', reject);
                    });
            });
        }

        //text
        getComponentInfo(OS: string): angular.IPromise<string> {
            return this.$q((resolve, reject) => {
                dinfraConfigue
                    .then(() => {
                        let res = new WriteStream();
                        getComponentInfoImpl(res, OS);
                        res.on('finish', () => {
                            this.uint8ToString(res.getData(), resolve);
                        });
                        res.on('error', reject);
                    });
            });
        }

        private getFileBlob(api: ResAPICallBack) {
            return this.$q((resolve, reject) => {
                dinfraConfigue
                    .then(() => {
                        let res = new WriteStream();
                        let headers = [];
                        res.writeHead = function (status, _headers) {
                            headers = _headers;
                        };
                        api(res);
                        res.on('finish', () => {
                            let contentType = headers['content-type'];
                            let newData = new Blob([res.getData()], { type: contentType });
                            resolve({
                                data: newData,
                                headers: function () { return headers; }
                            });
                        });
                        res.on('error', reject);
                    });
            });
        }
        //binary
        getFileContent(OS: string, path: string, type?: ti_common.file.ContentType, version?: string): angular.IPromise<string> {
            let params = { os: OS };

            if (!version) {
                version = "LATEST";
            }

            let ret, contentType;
            return this.getFileBlob((res: any) => {
                getFileImpl(params, path, version, res);
            })
                .catch((e) => {
                    this.$log.error(JSON.stringify(e))
                });
        }
		
		closeAgent(): angular.IPromise<any> {
			return dinfra.shutdown(0);
		}
    };

    angular.module('ti_common').service('ticAgentAPI', NWAgentAPI);
}
