import cp from 'child_process';
import fs from 'fs-extra-promise';
import glob from 'glob';
import path from 'path';
import iconv from 'iconv-lite';

export function shell(path: string, args: string[], verbase: boolean = true) {
    let stdout = "";
    let stderr = "";

    var cmd = `${path} ${args.join(" ")}`;
    if (verbase) {
        console.log(cmd);
    }
    let printStdoutBufferMessage = (message: Buffer) => {
        var str = message.toString();
        stdout += str;
        if (verbase) {
            console.log(str);
        }
    };
    let printStderrBufferMessage = (message: Buffer) => {
        var str = message.toString();
        stderr += str;
        if (verbase) {
            console.log(str);
        }
    };

    type Result = { code: number, stdout: string, stderr: string, path: string, args: any[] };

    return new Promise<Result>((reslove, reject) => {
        // path = "\"" + path + "\"";
        // var shell = cp.spawn(path + " " + args.join(" "));
        var shell = cp.spawn(path, args);
        shell.on("error", (message) => { console.log(message); });
        shell.stderr.on("data", printStderrBufferMessage);
        shell.stderr.on("error", printStderrBufferMessage);
        shell.stdout.on("data", printStdoutBufferMessage);
        shell.stdout.on("error", printStdoutBufferMessage);
        shell.on('exit', function (code) {
            if (code != 0) {
                if (verbase) {
                    console.log('Failed: ' + code);
                }
                reject({ code, stdout, stderr, path, args });
            }
            else {
                reslove({ code, stdout, stderr, path, args });
            }
        });
    });
}


export function shell2(command: string, args: string[]) {
    const cmd = command + " " + args.join(" ");
    return new Promise<string>((resolve, reject) => {
        const encoding = 'binary';
        const messageEncoding = 'cp936';
        var shell = cp.exec(cmd, { encoding }, (error, stdout, stderr) => {
            if (!error) {
                const stdoutString = iconv.decode(new Buffer(stdout.toString(), encoding), messageEncoding);
                resolve(stdoutString);
            }
            else {
                // console.log(stderr);
                const stderrString = iconv.decode(new Buffer(stderr, encoding), messageEncoding);
                console.log(stderrString)
                // console.log(stderrString)
                reject();
            }
        });
    })

}

export function doGlob(match: string, root: string) {

    return new Promise<string[]>((resolve, reject) => {
        glob(match, { cwd: root }, function (er, files) {
            resolve(files);
        })
    })

}

export function checkEgretProject(dirname: string) {
    const result = fs.existsSync(path.join(dirname, 'egretProperties.json'));
    if (!result) {
        throw 'not a egret project';
    }
}

export async function modifyJSON<T>(dest: string, modifyHook: (data: T) => T) {
    if (modifyHook) {
        const content = await fs.readJSONAsync(dest);
        fs.writeJSONAsync(dest, modifyHook(content))
    }

}


export function stringToUTF8Array(string: string): number[] {
    const result: number[] = [];

    for (let i = 0; i < string.length; i++) {
        const c = string.charAt(i);
        const cc = c.charCodeAt(0);

        if (cc > 0xFFFF) {
            throw new Error("InvalidCharacterError");
        }

        if (cc > 0x80) {
            if (cc < 0x07FF) {
                const c1 = (cc >>> 6) | 0xC0;
                const c2 = (cc & 0x3F) | 0x80;
                result.push(c1, c2);
            }
            else {
                const c1 = (cc >>> 12) | 0xE0;
                const c2 = ((cc >>> 6) & 0x3F) | 0x80;
                const c3 = (cc & 0x3F) | 0x80;
                result.push(c1, c2, c3);
            }
        }
        else {
            result.push(cc);
        }
    }

    return result;
}