package org.bdware.sc.boundry;

import org.bdware.sc.boundry.TimeIndex.Data;
import org.bdware.sc.index.LenVarTimeSerialIndex2;
import org.bdware.sc.util.HashUtil;
import wrp.jdk.nashorn.api.scripting.ScriptObjectMirror;
import wrp.jdk.nashorn.internal.objects.Global;
import wrp.jdk.nashorn.internal.objects.NativeArray;
import wrp.jdk.nashorn.internal.runtime.PropertyMap;
import wrp.jdk.nashorn.internal.runtime.ScriptObject;
import wrp.jdk.nashorn.internal.scripts.JO;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class AccountIndex {
    static Map<String, LenVarTimeSerialIndex2> fileMap = new HashMap<>();

    public static AccountIndex createIndex() {
        return new AccountIndex();
    }

    private static String getString(ScriptObjectMirror obj, String member) {
        Object mem = obj.getMember(member);
        if (mem != null && !(mem instanceof String)) {
            return mem.toString();
        }
        return (String) mem;
    }

    private static Integer getInteger(ScriptObjectMirror obj, String member) {
        Object mem = obj.getMember(member);
        if (mem != null && !(mem instanceof Integer)) {
            return Integer.valueOf(mem.toString());
        }
        return (Integer) mem;
    }

    private static Long getLong(ScriptObjectMirror obj, String member) {
        Object mem = obj.getMember(member);
        if (mem != null && !(mem instanceof Long)) {
            return Long.valueOf(mem.toString());
        }
        return (Long) mem;
    }

    public ScriptObject createFile(ScriptObjectMirror args) {
        JO ret = new JO(PropertyMap.newMap());
        if (!args.hasMember("account")) {
            ret.put("result", "Missing Argumemt", false);
            ret.put("status", "Error", false);
            return ret;
        }
        if (!args.hasMember("file")) {
            ret.put("result", "Missing Argumemt", false);
            ret.put("status", "Error", false);
            return ret;
        }
        if (!args.hasMember("dataLength")) {
            ret.put("result", "Missing Argumemt", false);
            ret.put("status", "Error", false);
            return ret;
        }
        try {
            Object file = args.get("file");
            if (!(file instanceof String)) {
                ret.put("result", "Illegal Type, file is not String", false);
                ret.put("status", "Error", false);
                return ret;
            }
            Object address = args.get("account");
            if (!(address instanceof String)) {
                ret.put("result", "Illegal Type, file is not String", false);
                ret.put("status", "Error", false);
                return ret;
            }
            String fileName = "./" + address + file;
            File f = new File(fileName + ".datasize");
            FileOutputStream fout = new FileOutputStream(f, false);
            Object dataLength = args.get("dataLength");
            int dataLengthInt = Integer.parseInt(dataLength.toString());
            for (int i = 0; i < dataLengthInt; i++)
                fout.write(1);
            fout.close();
            LenVarTimeSerialIndex2 index = getIndexFile(fileName);
            ret.put("dataLength", dataLength, false);
            ret.put("datasize", f.length(), false);

            ret.put("status", "Success", false);
            return ret;
        } catch (Exception e) {
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            e.printStackTrace(new PrintStream(bo));
            ret.put("status", "Success", false);
            ret.put("result", bo.toString(), false);
            return ret;
        }
    }

    public ScriptObject requestByTime(ScriptObjectMirror args) {
        JO ret = new JO(PropertyMap.newMap());
        if (!args.hasMember("account")) {
            ret.put("result", "Missing Argumemt", false);
            ret.put("status", "Error", false);
            return ret;
        }
        if (!args.hasMember("file")) {
            ret.put("result", "Missing Argumemt: file", false);
            ret.put("status", "Error", false);
            return ret;
        }
        if (!args.hasMember("startTime")) {
            ret.put("result", "Missing Argumemt: startTime", false);
            ret.put("status", "Error", false);
            return ret;
        }
        if (!args.hasMember("endTime")) {
            ret.put("result", "Missing Argumemt: endTime", false);
            ret.put("status", "Error", false);
            return ret;
        }

        try {
            LenVarTimeSerialIndex2 index = getIndexFile(getString(args, "account") + getString(args, "file"));
            long startTime = getLong(args, "startTime");
            long endTime = getLong(args, "endTime");
            List<byte[]> result = index.requestByTime(startTime, endTime);
            ret.put("status", "Success", false);
            NativeArray array = Global.allocate(new int[0]);
            ret.put("list", array, false);
            for (byte[] bytes : result) {
                JO data = new JO(PropertyMap.newMap());
                Data d = new Data(bytes);
                data.put("data", d.data, false);
                data.put("date", d.date, false);
                NativeArray.push(array, data);
            }
            return ret;
        } catch (Exception e) {
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            e.printStackTrace(new PrintStream(bo));
            ret.put("status", "Error", false);
            ret.put("data", bo.toString(), false);
            return ret;
        }
    }

    private LenVarTimeSerialIndex2 getIndexFile(String str) {
        LenVarTimeSerialIndex2 indexFile = fileMap.get(str);
        if (indexFile == null) {
            indexFile = new LenVarTimeSerialIndex2(str);
            fileMap.put(str, indexFile);
        }
        return indexFile;
    }

    public ScriptObject manullyIndex(ScriptObjectMirror args) {
        JO ret = new JO(PropertyMap.newMap());
        if (!args.hasMember("account")) {
            ret.put("result", "Missing Argumemt: account", false);
            ret.put("status", "Error", false);
            return ret;
        }
        if (!args.hasMember("date")) {
            ret.put("result", "Missing Argumemt: date", false);
            ret.put("status", "Error", false);
            return ret;
        }
        if (!args.hasMember("content")) {
            ret.put("result", "Missing Argumemt: content", false);
            ret.put("status", "Error", false);
            return ret;
        }
        if (!args.hasMember("file")) {
            ret.put("result", "Missing Argumemt: file", false);
            ret.put("status", "Error", false);
            return ret;
        }

        try {
            LenVarTimeSerialIndex2 index = getIndexFile(getString(args, "account") + getString(args, "file"));
            long date = getLong(args, "date");
            String content = getString(args, "content");
            index.manullyIndex(date, HashUtil.str16ToBytes(content));
            ret.put("status", "Success", false);
            return ret;
        } catch (Exception e) {
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            e.printStackTrace(new PrintStream(bo));
            ret.put("status", "Error", false);
            ret.put("data", bo.toString(), false);
            return ret;
        }
    }
}
