//=============================================================================================================
// ** Filename          : DSI-CharacterBook.js
// ** Last Updated      : Nov 15 2018
//=============================================================================================================
/*:
* @plugindesc v1.0 Release!
* @author dsiver144
* @help
* - Require DSI-WindowLayers to work properly.
* -------------------------------------------------------------------------------------
* > Script Calls:
* -------------------------------------------------------------------------------------
* 1. $gameSystem.unlockCharacterById(id)
* -> Unlock an character by their id.
* ex: $gameSystem.unlockCharacterById(0) : Unlock the first character configured
* in Plugin Manager.
* 
* 2. $gameSystem.unlockCharacterByName(name)
* -> Unlock an character by their name.
* ex: $gameSystem.unlockCharacterByName('Harold'); // Unlock the 'Harold'.
*
* 3. $gameSystem.unlockInfoTabsById(id, tabKey)
* -> Unlock an info tab of a specific character by their id.
* ex: $gameSystem.unlockInfoTabsById(0, 'tab1');
*
* 4. $gameSystem.unlockInfoTabsByName(name, tabKey)
* -> Unlock an info tab of a specific character by their name.
* ex: $gameSystem.unlockInfoTabsById('Alisa', 'secret');
* -------------------------------------------------------------------------------------
* > Conditional Brances Script Calls:
* -------------------------------------------------------------------------------------
* 1. $gameSystem.hasCharacterUnlockedById(id)
* -> Use this to check if you have unlocked a character by their id.
* 2. $gameSystem.hasCharacterUnlockedByName(name)
* -> Use this to check if you have unlocked a character by their name.
* ex: $gameSystem.hasCharacterUnlockedByName('Harold') // Check if Harold is
* unlocked or not.
* ------------------------------------------------------------------------------------
* > Others:
* ------------------------------------------------------------------------------------
* Yanfly Main Menu Manager Main Bind: this.commandCharacterBook.bind(this)
*
* @param Text 1
* @default Character Book
* 
* @param Character Config
* @type struct<CharacterInfo>[]
* @default ["{\"Name\":\"Harold\",\"Face File Name\":\"Actor1\",\"Face Index\":\"0\",\"Default Description\":\"\\\"One of the most \\\\\\\\c[5]useless\\\\\\\\c[0]\\\\nhero in the world! \\\\\\\\i[24]\\\\nZzZzZ...\\\"\",\"Info Tabs\":\"[\\\"{\\\\\\\"Key\\\\\\\":\\\\\\\"tab1\\\\\\\",\\\\\\\"Tab Name\\\\\\\":\\\\\\\"\\\\\\\\\\\\\\\\c[3]Ability\\\\\\\\\\\\\\\\c[0]\\\\\\\",\\\\\\\"Description\\\\\\\":\\\\\\\"\\\\\\\\\\\\\\\"His ultimate ability is \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\c[4]sleeping\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\c[0] \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\i[24] all day\\\\\\\\\\\\\\\\nwithout eating anything. Cool!\\\\\\\\\\\\\\\"\\\\\\\"}\\\",\\\"{\\\\\\\"Key\\\\\\\":\\\\\\\"secret\\\\\\\",\\\\\\\"Tab Name\\\\\\\":\\\\\\\"Secret...\\\\\\\",\\\\\\\"Description\\\\\\\":\\\\\\\"\\\\\\\\\\\\\\\"It's a secret...\\\\\\\\\\\\\\\"\\\\\\\"}\\\"]\"}","{\"Name\":\"Alisa\",\"Face File Name\":\"Actor3\",\"Face Index\":\"1\",\"Default Description\":\"\\\"She is the most beautiful \\\\\\\\c[6]princess\\\\\\\\c[0] in this world.\\\"\",\"Info Tabs\":\"[\\\"{\\\\\\\"Key\\\\\\\":\\\\\\\"tab1\\\\\\\",\\\\\\\"Tab Name\\\\\\\":\\\\\\\"Loves Music\\\\\\\",\\\\\\\"Description\\\\\\\":\\\\\\\"\\\\\\\\\\\\\\\"Has loved music since she was a child, \\\\\\\\\\\\\\\\nand originally wanted to attend a music \\\\\\\\\\\\\\\\nacademy instead of being a Queen.\\\\\\\\\\\\\\\"\\\\\\\"}\\\",\\\"{\\\\\\\"Key\\\\\\\":\\\\\\\"secret\\\\\\\",\\\\\\\"Tab Name\\\\\\\":\\\\\\\"\\\\\\\\\\\\\\\\c[27]Secret...\\\\\\\",\\\\\\\"Description\\\\\\\":\\\\\\\"\\\\\\\\\\\\\\\"It's a secret...\\\\\\\\\\\\\\\"\\\\\\\"}\\\",\\\"{\\\\\\\"Key\\\\\\\":\\\\\\\"tab3\\\\\\\",\\\\\\\"Tab Name\\\\\\\":\\\\\\\"Test Tab\\\\\\\",\\\\\\\"Description\\\\\\\":\\\\\\\"\\\\\\\\\\\\\\\"random text here...\\\\\\\\\\\\\\\\nABCDEFGH...\\\\\\\\\\\\\\\\n0123456789...\\\\\\\\\\\\\\\"\\\\\\\"}\\\"]\"}"]
*
*/
/*~struct~CharacterInfo:
* @param Name
*
* @param Face File Name
*
* @param Face Index
*
* @param Default Description
* @type note
*
* @param Info Tabs
* @type struct<InfoTab>[]
*/
/*~struct~InfoTab:
* @param Key
* @param Tab Name
* @desc Important! Used in script calls. Much be unique for each tab.
*
* @param Description
* @type note
*/

function Scene_CharacterBook() {
    this.initialize.apply(this, arguments);
};

function Window_CharacterNameList() {
    this.initialize.apply(this, arguments);
};

function Window_CharacterInfo() {
    this.initialize.apply(this, arguments);
};

function Window_CharacterInfoTabs() {
    this.initialize.apply(this, arguments);
};

var Imported = Imported || {};
Imported['DSI-CharacterBookSystem'] = 1.0;

(function(){
    
    var params = PluginManager.parameters('DSI-CharacterBook');
    var $P = {}
    $P.array = JSON.parse(params['Character Config']);
    var $characterData = [];
    for (var i = 0; i < $P.array.length; i++) {
        var character = JSON.parse($P.array[i]);
        character['Default Description'] = JSON.parse(character['Default Description']);
        character['Face Index'] = Number(character['Face Index']);
        var tabArray = JSON.parse(character['Info Tabs']);
        for (var j = 0; j < tabArray.length; j++) {
            tabArray[j] = JSON.parse(tabArray[j]);
            tabArray[j].Description = JSON.parse(tabArray[j].Description);
        }
        character['Info Tabs'] = tabArray;
        $characterData.push(character);
    };
    
    var DSI_CharacterBook_Game_System_initialize = Game_System.prototype.initialize;
    Game_System.prototype.initialize = function() {
        DSI_CharacterBook_Game_System_initialize.apply(this, arguments);
        this._unlockedCharacters = {}
    };
    
    Game_System.prototype.unlockCharacterById = function(index) {
        if (!this._unlockedCharacters.hasOwnProperty(index)) {
            this._unlockedCharacters[index] = {}
            this._unlockedCharacters[index].unlockedTabs = {}
            return true;
        }
        return false;
    };
    
    Game_System.prototype.hasCharacterUnlockedById = function(index) {
        return this._unlockedCharacters.hasOwnProperty(index);
    };
    
    Game_System.prototype.hasCharacterUnlockedByName = function(name) {
        var index = -1;
        for (var i = 0; i < $characterData.length; i++) {
            if ($characterData[i].Name === name) {
                index = i;
                break;
            }
        }
        return this._unlockedCharacters.hasOwnProperty(index);
    };
    
    Game_System.prototype.getCharacterIdByName = function(name) {
        var index = -1;
        for (var i = 0; i < $characterData.length; i++) {
            if ($characterData[i].Name === name) {
                index = i;
                break;
            }
        }
        return index;
    };
    
    Game_System.prototype.getCharacterById = function(index) {
        return $characterData[index];
    };
    
    Game_System.prototype.getIdByCharacter = function(character) {
        for (var i = 0; i < $characterData.length; i++) {
            if (character === $characterData[i]) return i;
        }
        return -1;
    };
    
    Game_System.prototype.unlockCharacterByName = function(name) {
        var index = -1;
        for (var i = 0; i < $characterData.length; i++) {
            if ($characterData[i].Name === name) {
                index = i;
                break;
            }
        }
        if (index === -1) return false;
        return this.unlockCharacterById(index);
    };
    
    Game_System.prototype.unlockInfoTabsById = function(index, tabKey) {
        if (this.hasCharacterUnlockedById(index)) {
            if (index === -1) return false;
            this._unlockedCharacters[index].unlockedTabs[tabKey] = true;
            return true;
        }
        return false;
    };
    
    Game_System.prototype.unlockInfoTabsByName = function(name, tabKey) {
        if (this.hasCharacterUnlockedByName(name)) {
            var index = this.getCharacterIdByName(name);
            if (index === -1) return false;
            this._unlockedCharacters[index].unlockedTabs[tabKey] = true;
            return true;
        }
        return false;
    };
    
    Game_System.prototype.hasInfoTabsUnlockedById = function(index, tabKey) {
        if (this.hasCharacterUnlockedById(index)) {
            if (index === -1) return false;
            console.log('Here', tabKey, this._unlockedCharacters[index].unlockedTabs[tabKey]);
            return this._unlockedCharacters[index].unlockedTabs[tabKey];
        }
        return false;
    };
    
    Game_System.prototype.displayCharacters = function() {
        var data = [];
        for (var index = 0; index < $characterData.length; index++) {
            data[index] = null;
            if (this.hasCharacterUnlockedById(index)) data[index] = this.getCharacterById(index);
        }
        return data;
    };
    
    Game_System.prototype.displayInfoTabs = function(character) {
        if (character === null) return [];
        var data = character['Info Tabs'];
        var index = this.getIdByCharacter(character);
        console.log('Index = ', index);
        var result = [];
        for (var i = 0; i < data.length; i++) {
            var tabKey = data[i].Key;
            result[i] = null;
            if (this.hasInfoTabsUnlockedById(index, tabKey)) {
                result[i] = data[i];
            }
        }
        return result;
    };
    
    Scene_Menu.prototype.commandCharacterBook = function() {
        SceneManager.push(Scene_CharacterBook);
    };
    
    Scene_CharacterBook.prototype = Object.create(Scene_MenuBase.prototype);
    Scene_CharacterBook.prototype.constructor = Scene_CharacterBook;
    
    Scene_CharacterBook.prototype.create = function() {
        Scene_MenuBase.prototype.create.call(this);
        this.createAllWindows();
    };
    
    Scene_CharacterBook.prototype.createAllWindows = function() {
        var ww = Graphics.width - 24 * 2;
        var wx = 24;
        var wy = 24;
        var wh = 72;
        this._titleWindow = new Window_Base(wx, wy, ww, wh);
        this._titleWindow.drawText(params['Text 1'], 0, 0, this._titleWindow.contentsWidth(), 'center');
        this.addWindow(this._titleWindow);
        
        this._listWindow = new Window_CharacterNameList(wx, wy + wh + 32);
        this.addWindow(this._listWindow);
        this._listWindow.setHandler('cancel', this.popScene.bind(this));
        
        wx = this._listWindow.x + this._listWindow.width + 24;
        wy = this._listWindow.y;
        ww = Graphics.width - 24 * 3 - this._listWindow.width;
        wh = this._listWindow.windowHeight();
        console.log(wx, wy, ww, wh);
        this._infoWindow = new Window_CharacterInfo(wx, wy, ww, wh);
        this._listWindow.setInfoWindow(this._infoWindow);
        
        this.addWindow(this._infoWindow);
        
        wx = this._infoWindow.x; 
        wy = this._infoWindow.y + 46 + Window_Base._faceHeight + 24;
        ww = this._infoWindow.width;
        wh = this._infoWindow.height - Window_Base._faceHeight - 46 - 24;
        this._tabList = new Window_CharacterInfoTabs(wx, wy, ww, wh);
        this._tabList.opacity = 0;
        this._tabList.backOpacity = 0;
        this._listWindow.setTabWindow(this._tabList);
        this._tabList.deactivate();
        this._listWindow.setHandler('ok', this.onListOk.bind(this));
        this._tabList.setHandler('cancel', this.onTabCancel.bind(this));
        
        this.addWindow(this._tabList);
    };
    
    Scene_CharacterBook.prototype.onListOk = function() {
        this._tabList.activate();
        this._tabList.select(0);
    };
    
    Scene_CharacterBook.prototype.onTabCancel = function() {
        this._tabList.deselect();
        this._listWindow.activate();
    };
    
    if (Imported['DSI-WindowLayers']) {
        Scene_CharacterBook.prototype.createWindowLayer = function() {
            var width = Graphics.boxWidth;
            var height = Graphics.boxHeight;
            var x = (Graphics.width - width) / 2;
            var y = (Graphics.height - height) / 2;
            this._windowLayer = new WindowLayerEx();
            this._windowLayer.move(x, y, width, height);
            this.addChild(this._windowLayer);
        }
    };
    
    Window_CharacterNameList.prototype = Object.create(Window_Command.prototype);
    Window_CharacterNameList.prototype.constructor = Window_CharacterNameList;
    
    Window_CharacterNameList.prototype.makeCommandList = function() {
        var data = $gameSystem.displayCharacters();
        for (var i = 0; i < data.length; i++) {
            this.addCommand('Name Here', i, data[i] !== null, data[i]);
        }
    };
    
    Window_CharacterNameList.prototype.windowHeight = function() {
        return Graphics.height - 24 * 3 - 72;
    };
    
    Window_CharacterNameList.prototype.commandExt = function(index) {
        return this._list[index].ext;
    };
    
    Window_CharacterNameList.prototype.drawItem = function(index) {
        var rect = this.itemRectForText(index);
        var align = this.itemTextAlign();
        var data = this.commandExt(index);
        this.resetTextColor();
        this.changePaintOpacity(this.isCommandEnabled(index));
        if (data === null) {
            this.drawText('??????????????', rect.x, rect.y, rect.width, align);
        } else {
            this.drawText(data.Name, rect.x, rect.y, rect.width, align);
        }
    };
    
    Window_CharacterNameList.prototype.callUpdateHelp = function() {
        if (this.active && this._infoWindow) {
            this._infoWindow.updateCharacter(this.currentExt());
        }
        if (this.active && this._tabWindow) {
            this._tabWindow.setCharacter(this.currentExt());
            console.log(this._tabWindow);
        }
    };
    
    Window_CharacterNameList.prototype.setInfoWindow = function(window) {
        this._infoWindow = window;
        this.callUpdateHelp();
    };
    
    Window_CharacterNameList.prototype.setTabWindow = function(window) {
        this._tabWindow = window;
        this.callUpdateHelp();
    };
    
    Window_CharacterInfo.prototype = Object.create(Window_Base.prototype);
    Window_CharacterInfo.prototype.constructor = Window_CharacterInfo;
    
    Window_CharacterInfo.prototype.calcTextHeight = function(textState, all) {
        var lastFontSize = this.contents.fontSize;
        var textHeight = 0;
        var lines = textState.text.slice(textState.index).split('\n');
        var maxLines = all ? lines.length : 1;

        for (var i = 0; i < maxLines; i++) {
            var maxFontSize = this.contents.fontSize;
            var regExp = /\x1b[\{\}]/g;
            for (;;) {
                var array = regExp.exec(lines[i]);
                if (array) {
                    if (array[0] === '\x1b{') {
                        this.makeFontBigger();
                    }
                    if (array[0] === '\x1b}') {
                        this.makeFontSmaller();
                    }
                    if (maxFontSize < this.contents.fontSize) {
                        maxFontSize = this.contents.fontSize;
                    }
                } else {
                    break;
                }
            }
            textHeight += maxFontSize + 4;
        }

        this.contents.fontSize = lastFontSize;
        return textHeight;
    };
    
    Window_CharacterInfo.prototype.updateCharacter = function(character) {
        this.contents.clear();
        var cw = this.contentsWidth();
        var ch = this.contentsHeight();
        if (character === null) {
            this.contents.paintOpacity = 50;
            this.contents.fillRect(0, 0, cw, ch, this.systemColor());
            this.contents.paintOpacity = 255;
            this.contents.drawText('- No Data -', 0, 0, cw, ch, 'center');
        } else {
            // Preload Face Image
            var bitmap = ImageManager.loadFace(character['Face File Name']);
            if (bitmap.width <= 0) {
                return setTimeout(this.updateCharacter.bind(this, character), 5);
            }
            // Draw Stuff Below
            this.changeTextColor(this.textColor(14));
            this.drawText(character.Name, 0, 0, cw, 'left');
            this.changeTextColor(this.textColor(0));
            this.drawHorzLine(34,3);
            this.contents.paintOpacity = 100;
            this.contents.fillRect(0, 46, Window_Base._faceWidth, Window_Base._faceHeight, this.systemColor());
            this.contents.paintOpacity = 255;
            this.drawFace(character['Face File Name'], character['Face Index'], 0, 46, Window_Base._faceWidth, Window_Base._faceHeight);
            this.drawTextEx(character['Default Description'], Window_Base._faceWidth + 16, 46);
            this.drawHorzLine(46 + Window_Base._faceHeight + 8, 3);
        }
    };
    
    Window_CharacterInfo.prototype.drawHorzLine = function(y, height) {
        if (height === undefined) height = 1;
        this.contents.fillRect(0, y, this.contentsWidth(), height, this.textColor(0));
    };
    
    Window_CharacterInfoTabs.prototype = Object.create(Window_Command.prototype);
    Window_CharacterInfoTabs.prototype.constructor = Window_CharacterInfoTabs;
    
    Window_CharacterInfoTabs.prototype.initialize = function(x, y, width, height) {
        this.clearCommandList();
        this.makeCommandList();
        Window_Selectable.prototype.initialize.call(this, x, y, width, height);
        this.refresh();
        this.select(0);
        this.activate();
    };
    
    Window_CharacterInfoTabs.prototype.itemHeight = function() {
        return this.contentsHeight() / 2;
    };
    
    Window_CharacterInfoTabs.prototype.commandExt = function(index) {
        return this._list[index].ext;
    };
    
    Window_CharacterInfoTabs.prototype.setCharacter = function(character) {
        this._character = character;
        this.refresh();
        this.deselect();
    };
    
    // For Compatible with MOG_MenuBackground
    Window_CharacterInfoTabs.prototype.needUpdateBackOpacity = function() {
       return false;
    };
    
    Window_CharacterInfoTabs.prototype.makeCommandList = function() {
        if (this._character === undefined) return;
        var data = $gameSystem.displayInfoTabs(this._character);
        console.log('Data :' , data);
        for (var i = 0; i < data.length; i++) {
            this.addCommand('???', i, true, data[i]);
        }
    };
    
    Window_CharacterInfoTabs.prototype.drawItem = function(index) {
        var rect = this.itemRectForText(index);
        var align = this.itemTextAlign();
        var data = this.commandExt(index);
        this.resetTextColor();
        this.changePaintOpacity(this.isCommandEnabled(index));
        if (data === null) {
            this.changeTextColor(this.systemColor());
            this.drawText('??????????????', rect.x, rect.y, rect.width, align);
            this.drawHorzLine(rect.y + 34, 2);
        } else {
            this.drawHorzLine(rect.y + 34, 2);
            this.drawTextEx(data['Tab Name'], rect.x, rect.y);
            this.drawTextEx(data.Description, rect.x, rect.y + 36);
        }
    };
    
    Window_CharacterInfoTabs.prototype.drawHorzLine = function(y, height) {
        if (height === undefined) height = 1;
        this.contents.fillRect(6, y, this.contentsWidth() - 12, height, this.textColor(0));
    };
    
})();