"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Game = void 0;
const axios_1 = __importDefault(require("axios"));
const fs_1 = __importDefault(require("fs"));
const Mage_1 = require("./Mage");
const Merchant_1 = require("./Merchant");
const Observer_1 = require("./Observer");
const PingCompensatedCharacter_1 = require("./PingCompensatedCharacter");
const Priest_1 = require("./Priest");
const Ranger_1 = require("./Ranger");
const Rogue_1 = require("./Rogue");
const Warrior_1 = require("./Warrior");
class Game {
    constructor() {
    }
    static async disconnect() {
        await this.stopAllCharacters();
        await this.stopAllObservers();
    }
    static async getGData() {
        if (this.G)
            return this.G;
        console.debug("Updating 'G' data...");
        const response = await axios_1.default.get("http://adventure.land/data.js");
        if (response.status == 200) {
            const matches = response.data.match(/var\s+G\s*=\s*(\{.+\});/);
            this.G = JSON.parse(matches[1]);
            console.debug("Updated 'G' data!");
            return this.G;
        }
        else {
            console.error(response);
            console.error("Error fetching http://adventure.land/data.js");
        }
    }
    static async getMail(all = true) {
        if (!this.user)
            return Promise.reject("You must login first.");
        let data = await axios_1.default.post("http://adventure.land/api/pull_mail", "method=pull_mail&arguments={}", { headers: { "cookie": `auth=${this.user.userID}-${this.user.userAuth}` } });
        const mail = [];
        while (data.data.length > 0) {
            mail.push(...data.data[0].mail);
            if (all && data.data[0].more) {
                data = await axios_1.default.post("http://adventure.land/api/pull_mail", `method=pull_mail&arguments={"cursor":"${data.data[0].cursor}"}`, { headers: { "cookie": `auth=${this.user.userID}-${this.user.userAuth}` } });
            }
            else {
                break;
            }
        }
        return mail;
    }
    static async getMerchants() {
        if (!this.user)
            return Promise.reject("You must login first.");
        const merchants = [];
        const data = await axios_1.default.post("http://adventure.land/api/pull_merchants", "method=pull_merchants", { headers: { "cookie": `auth=${this.user.userID}-${this.user.userAuth}` } });
        for (const datum of data.data) {
            if (datum.type == "merchants") {
                for (const char of datum.chars) {
                    merchants.push(char);
                }
            }
        }
        return merchants;
    }
    static async markMailAsRead(mailID) {
        if (!this.user)
            return Promise.reject("You must login first.");
        const data = await axios_1.default.post("http://adventure.land/api/read_mail", `method=read_mail&arguments={"mail": "${mailID}"}`, { headers: { "cookie": `auth=${this.user.userID}-${this.user.userAuth}` } });
        return data.data[0];
    }
    static async login(email, password) {
        console.debug("Logging in...");
        const login = await axios_1.default.post("https://adventure.land/api/signup_or_login", `method=signup_or_login&arguments={"email":"${email}","password":"${password}","only_login":true}`);
        let loginResult;
        for (const datum of login.data) {
            if (datum.message) {
                loginResult = datum;
                break;
            }
        }
        if (loginResult && loginResult.message == "Logged In!") {
            console.debug("Logged in!");
            for (const cookie of login.headers["set-cookie"]) {
                const result = /^auth=(.+?);/.exec(cookie);
                if (result) {
                    this.user = {
                        userID: result[1].split("-")[0],
                        userAuth: result[1].split("-")[1]
                    };
                    break;
                }
            }
        }
        else if (loginResult && loginResult.message) {
            console.error(loginResult.message);
            return Promise.reject(loginResult.message);
        }
        else {
            console.error(login.data);
            return Promise.reject();
        }
        return this.updateServersAndCharacters();
    }
    static async loginJSONFile(path) {
        const data = JSON.parse(fs_1.default.readFileSync(path, "utf8"));
        return this.login(data.email, data.password);
    }
    static async startCharacter(cName, sRegion, sID, cType) {
        if (!this.user)
            return Promise.reject("You must login first.");
        if (!this.characters)
            await this.updateServersAndCharacters();
        if (!this.G)
            await this.getGData();
        const userID = this.user.userID;
        const userAuth = this.user.userAuth;
        const characterID = this.characters[cName].id;
        try {
            let player;
            if (cType == "mage")
                player = new Mage_1.Mage(userID, userAuth, characterID, Game.G, this.servers[sRegion][sID]);
            else if (cType == "merchant")
                player = new Merchant_1.Merchant(userID, userAuth, characterID, Game.G, this.servers[sRegion][sID]);
            else if (cType == "priest")
                player = new Priest_1.Priest(userID, userAuth, characterID, Game.G, this.servers[sRegion][sID]);
            else if (cType == "ranger")
                player = new Ranger_1.Ranger(userID, userAuth, characterID, Game.G, this.servers[sRegion][sID]);
            else if (cType == "rogue")
                player = new Rogue_1.Rogue(userID, userAuth, characterID, Game.G, this.servers[sRegion][sID]);
            else if (cType == "warrior")
                player = new Warrior_1.Warrior(userID, userAuth, characterID, Game.G, this.servers[sRegion][sID]);
            else
                player = new PingCompensatedCharacter_1.PingCompensatedCharacter(userID, userAuth, characterID, Game.G, this.servers[sRegion][sID]);
            await player.connect();
            this.players[cName] = player;
            return player;
        }
        catch (e) {
            return Promise.reject(e);
        }
    }
    static async startMage(cName, sRegion, sID) {
        return await Game.startCharacter(cName, sRegion, sID, "mage");
    }
    static async startMerchant(cName, sRegion, sID) {
        return await Game.startCharacter(cName, sRegion, sID, "merchant");
    }
    static async startPriest(cName, sRegion, sID) {
        return await Game.startCharacter(cName, sRegion, sID, "priest");
    }
    static async startRanger(cName, sRegion, sID) {
        return await Game.startCharacter(cName, sRegion, sID, "ranger");
    }
    static async startRogue(cName, sRegion, sID) {
        return await Game.startCharacter(cName, sRegion, sID, "rogue");
    }
    static async startWarrior(cName, sRegion, sID) {
        return await Game.startCharacter(cName, sRegion, sID, "warrior");
    }
    static async startObserver(region, id) {
        try {
            const g = await Game.getGData();
            const observer = new Observer_1.Observer(this.servers[region][id], g, true);
            await observer.connect();
            this.observers[this.servers[region][id].key] = observer;
            return observer;
        }
        catch (e) {
            return Promise.reject(e);
        }
    }
    static async stopAllCharacters() {
        for (const characterName in this.players)
            await this.stopCharacter(characterName);
    }
    static async stopAllObservers() {
        for (const region in this.observers)
            for (const id in this.observers[region])
                await this.stopObserver(region, id);
    }
    static async stopCharacter(characterName) {
        await this.players[characterName].disconnect();
        delete this.players[characterName];
    }
    static async stopObserver(region, id) {
        this.observers[this.servers[region][id].key].socket.close();
        this.observers[this.servers[region][id].key].socket.removeAllListeners();
        delete this.observers[region][id];
    }
    static async updateServersAndCharacters() {
        if (!this.user)
            return Promise.reject("You must login first.");
        const data = await axios_1.default.post("http://adventure.land/api/servers_and_characters", "method=servers_and_characters&arguments={}", { headers: { "cookie": `auth=${this.user.userID}-${this.user.userAuth}` } });
        if (data.status == 200) {
            for (const serverData of data.data[0].servers) {
                if (!this.servers[serverData.region])
                    this.servers[serverData.region] = {};
                this.servers[serverData.region][serverData.name] = serverData;
            }
            for (const characterData of data.data[0].characters) {
                this.characters[characterData.name] = characterData;
            }
            return Promise.resolve(true);
        }
        else {
            console.error(data);
        }
        return Promise.reject("Error fetching http://adventure.land/api/servers_and_characters");
    }
}
exports.Game = Game;
Game.servers = {};
Game.characters = {};
Game.players = {};
Game.observers = {};
//# sourceMappingURL=Game.js.map