
/** DIALOGUE **************************************************************************************/

Dialogue = {

    // Music
    'help1': {
        type        : 'notification',
        text        : 'Use the arrows keys to move, spacebar to interact with someone, and enter to submit.'
    },

    'wetDreams': {
        type        : 'notification',
        text        : '<a href="http://ocremix.org/remix/OCR02727" target="_blank">Wet Dreams, by Phonetic Hero</a>'
    },

    'game_load': {
        type        : 'dialogue',
        emote       : 'happiness',
        triggeredText: function(npc) {
            npc.dialogueId = "step1_start";
        },
        goTo        : 'game_load2',
        text    : "Welcome! I'm a clerk who has been tasked with helping you fill out this form."
    },

    'game_load2': {
        type        : 'dialogue',
        emote       : 'happiness',
        text    : "The enter key can be used to speak to people and end dialogues. After closing this dialogue, use the arrow keys to walk over to me, and then hit enter to speak with me.",
        action: function(npc) {
            setTimeout(function(){
                npc.npc('emote', 'question');
            }, 500);
        },
        end : true
    },




    'clerk_notready': {
        type        : 'dialogue',
        text        : "I'm not ready to speak to you yet, please go talk to my colleague.",
        emote       : 'question',
        end         : true
    },

    'step1_start': {
        type        : 'dialogue',
        text        : "To begin with, let's record your children's information.",
        emote       : 'question',
        goTo        : 'step1_q1'
    },

    'step1_q1': {
        type    : 'input',
        emote   : 'question',
        label   : 'How many children do you have? (hit enter when done)',
        goTo    : 'step1_q2',
        action: function(npc, value) {
            var total_children = parseInt(value);
            Game.children_left_to_fill_out = total_children;
            for (var i=1; i<=10; i++) {
                $('#child'+i).hide();
            }
            for (var i=1; i<=total_children; i++) {
                $('#child'+i).show();
                if ($('#child'+i).data().npc.completedme) {
                    Game.children_left_to_fill_out -= 1;
                }
            }
        }
    },

    'step1_q2': {
        type        : 'dialogue',
        text        : "Excellent! I created avatars to represent each child. Continue by talking to them!",
        emote       : 'happiness',
        end         : true,
        action      : function(npc) {
            if (npc && !npc.data().npc['frozen']) {
                var move_directions = [];

                move_directions.push('right');
                move_directions.push('right');
                move_directions.push('up');

                npc.npc('move', move_directions);
                setTimeout(function(){
                    npc.find('.npc-sprite').removeClass('up').addClass('down');
                }, 1500);
                npc.data().npc['frozen'] = true;
                //npc.data().npc.dialogueId = "step1_q1";
            }
        }
    },

    'dchi01': {
        type        : 'dialogue',
        emote       : 'question',
        text        : "I'm an avatar representing your child! Help fill out more information about me.",
        goTo        : 'ichi01'
    },


    'ichi01': {
        type    : 'input',
        goTo    : 'ichi02',
        emote   : 'question',
        label : 'What is my name? (First name, middle initial, last name)',
        action: function(npc, value) {
            var npc_id = npc.data()['npc'].id;
            if (!(npc_id in Game.formData['children'])) {
                Game.formData['children'][npc_id] = {};
            }
            Game.formData['children'][npc_id]['name'] = value;
        }
    },

    'ichi02': {
        type    : 'choice',
        emote       : 'question',
        choices : [
            {
                label       : 'I am not a student',
                goTo        : 'ichi03',
                action: function(npc, value) {
                    var npc_id = npc.data()['npc'].id;
                    if (!(npc_id in Game.formData['children'])) {
                        Game.formData['children'][npc_id] = {};
                    }
                    Game.formData['children'][npc_id]['student'] = false;
                }
            },
            {
                label       : 'I am a student',
                goTo        : 'ichi03',
                action: function(npc, value) {
                    var npc_id = npc.data()['npc'].id;
                    if (!(npc_id in Game.formData['children'])) {
                        Game.formData['children'][npc_id] = {};
                    }
                    Game.formData['children'][npc_id]['student'] = true;
                }
            }
        ]
    },

    'ichi03': {
        type    : 'choice',
        emote       : 'question',
        choices : [
            {
                label       : 'I am not a foster child',
                goTo        : 'ichi04a',
                action: function(npc, value) {
                    var npc_id = npc.data()['npc'].id;
                    if (!(npc_id in Game.formData['children'])) {
                        Game.formData['children'][npc_id] = {};
                    }
                    Game.formData['children'][npc_id]['foster_child'] = false;
                }
            },
            {
                label       : 'I am a foster child',
                goTo        : 'ichi04a',
                action: function(npc, value) {
                    var npc_id = npc.data()['npc'].id;
                    if (!(npc_id in Game.formData['children'])) {
                        Game.formData['children'][npc_id] = {};
                    }
                    Game.formData['children'][npc_id]['foster_child'] = true;
                }
            }
        ]
    },

    'ichi04a': {
        type    : 'choice',
        emote       : 'question',
        choices : [
            {
                label       : 'I am not homeless / a migrate / a runaway',
                goTo        : 'ichi04b',
                action: function(npc, value) {
                    var npc_id = npc.data()['npc'].id;
                    if (!(npc_id in Game.formData['children'])) {
                        Game.formData['children'][npc_id] = {};
                    }
                    Game.formData['children'][npc_id]['homeless'] = false;
                }
            },
            {
                label       : 'I am homeless / a migrate / a runaway',
                goTo        : 'ichi04b',
                action: function(npc, value) {
                    var npc_id = npc.data()['npc'].id;
                    if (!(npc_id in Game.formData['children'])) {
                        Game.formData['children'][npc_id] = {};
                    }
                    Game.formData['children'][npc_id]['homeless'] = true;
                }
            }
        ]
    },

    'ichi04b': {
        type    : 'inputincome',
        goTo    : 'ichi05',
        emote       : 'question',
        label : 'How much income do I earn?',
        action: function(npc, value) {
            if (npc && value) {
                var npc_id = npc.data()['npc'].id;
                Game.formData['children'][npc_id]['income'] = value;
            }
        }
    },

    'ichi05': {
        type        : 'dialogue',
        text        : "...",
        emote       : 'question',
        dynamicText: function(npc){
            var c = Game.formData.children[npc.data().npc.id];
            recap_statement = "";
            recap_statement += "My name is "+c.name+". ";
            if (c.student) {
                recap_statement += "I am a student. ";
            }
            else {
                recap_statement += "I am not a student. ";
            }
            if (c.foster_child) {
                recap_statement += "I am a foster child. ";
            }
            else {
                recap_statement += "I am not a foster child. ";
            }
            if (c.homeless) {
                recap_statement += "I am homeless / a migrate / a runaway. ";
            }
            else {
                recap_statement += "I am not homeless / a migrate / a runaway. ";
            }
            if (parseInt(c.income)) {
                recap_statement += "I earn $"+c.income+". ";
            }
            recap_statement += "Is this correct?";
            return recap_statement;
        },
        goTo        : 'ichi06'
    },

    'ichi06': {
        type    : 'choice',
        emote       : 'question',
        choices : [
            {
                label       : 'Yes',
                goTo        : 'ichi07'
            },

            {
                label       : 'No',
                goTo        : 'ichi01'
            }
        ]
    },

    'ichi07': {
        type        : 'dialogue',
        text        : "Thanks! I'm good to go!",
        end         : true,
        emote       : 'question',
        triggeredText: function(npc) {
            npc.dialogueId = "step1_start";
        },
        action      : function(npc) {
            if (npc) {

                if (!npc.data().npc.completedme) {
                    //If first time completing this child, mark 'em done.
                    Game.children_left_to_fill_out -= 1;
                }
                npc.data().npc.completedme = true;

                var move_directions = [];

                move_directions.push('up');
                move_directions.push('up');

                move_directions.push('up');
                move_directions.push('up');
                move_directions.push('up');

                npc.npc('move', move_directions);

                setTimeout(function(){
                    npc.find('.npc-sprite').removeClass('up').addClass('down');
                }, 2000);

                if (Game.children_left_to_fill_out <= 0) {
                    all_foster_or_homeless_children = true;
                    for(var o in Game.formData.children) {
                        if (!Game.formData.children[o].foster_child) {
                            if (!Game.formData.children[o].homeless) {
                                all_foster_or_homeless_children = false;
                            }
                        }
                    }

                    if (all_foster_or_homeless_children) {
                        //skip to step 4
                        setTimeout(function(){
                            var newDialogue = Dialogue["step4_npcstart"];
                            $('#n005').npc('talk', newDialogue);
                            $('#n005').data('npc').dialogueId = "step4_start";
                        }, 1000);
                    }
                    else {
                        setTimeout(function(){
                            var newDialogue = Dialogue["step2_npcstart"];
                            $('#n003').npc('talk', newDialogue);
                            $('#n003').data('npc').dialogueId = "step2_start";
                        }, 1000);
                    }
                }
            }
        }
    },

    'step2_npcstart': {
        type        : 'dialogue',
        text        : "Excellent! Come talk to me to move on to the next step.",
        emote       : 'question',
        end         : true,
        action      : function(npc) {
            if (npc && !npc.data().npc['frozen']) {
                npc.data().npc['frozen'] = true;

                var move_directions = [];

                move_directions.push('down');
                move_directions.push('down');
                move_directions.push('down');
                move_directions.push('down');
                move_directions.push('right');

                npc.npc('move', move_directions);

                setTimeout(function(){
                    npc.find('.npc-sprite').removeClass('right').addClass('down');
                }, 2000);

                setTimeout(function(){
                    npc.npc('emote', 'question');
                }, 500);
            }
        }
    },

    'step2_start': {
        type        : 'dialogue',
        emote       : 'question',
        text        : "Do any Household Members (including you) currently participate in one or more of the following assistance programs: SNAP, TANF, or FDPIR?",
        goTo        : 'step2_choice'
    },

    'step2_choice': {
        type    : 'choice',
        emote       : 'question',
        choices : [
            {
                label       : 'No (we do not partipicate in SNAP, TANF, or FDPIR)',
                goTo        : 'step2_end'
            },
            {
                label       : 'Yes (we participate in SNAP, TANF, or FDPIR)',
                goTo        : 'step2_followup'
            }
        ]
    },

    'step2_followup': {
        type    : 'input',
        goTo    : 'step2_end',
        emote       : 'question',
        label : 'What is your case number?',
        action: function(npc, value) {
            Game.formData['case_number'] = value;
        }
    },

    'step2_end': {
        type        : 'dialogue',
        text        : "Excellent! We're done here, move on to the next room.",
        emote       : 'question',
        end         : true,
        action: function(npc, value) {
            if (npc) {
                if (Game.formData['case_number']) {
                    //skip to step 4
                    setTimeout(function(){
                        var newDialogue = Dialogue["step4_npcstart"];
                        $('#n005').npc('talk', newDialogue);
                        $('#n005').data('npc').dialogueId = "step4_start";
                    }, 1000);
                }
                else {
                    setTimeout(function(){
                        var newDialogue = Dialogue["step3_npcstart"];
                        $('#n004').npc('talk', newDialogue);
                        $('#n004').data('npc').dialogueId = "step3_start";
                    }, 1000);
                }
            }
        }
    },

    'step3_npcstart': {
        type        : 'dialogue',
        text        : "Excellent! Come talk to me to move on to the next step.",
        emote       : 'happiness',
        end         : true,
        action      : function(npc) {
            if (npc && !npc.data().npc['frozen']) {
                npc.data().npc['frozen'] = true;
                var move_directions = [];

                move_directions.push('down');
                move_directions.push('down');
                move_directions.push('down');
                move_directions.push('down');
                move_directions.push('left');

                npc.npc('move', move_directions);

                setTimeout(function(){
                    npc.find('.npc-sprite').removeClass('left').addClass('down');
                }, 2000);

                setTimeout(function(){
                    npc.npc('emote', 'question');
                }, 500);
            }
        }
    },

    'step3_start': {
        type        : 'dialogue',
        emote       : 'question',
        text        : "We're going to finish gathering details about your household here.",
        goTo        : 'step3_i1'
    },

    'step3_i1': {
        type    : 'input',
        emote       : 'question',
        label   : 'How many adults are in your household?',
        goTo    : 'step3_i2',
        action: function(npc, value) {
            var total_adults = parseInt(value);
            Game.adults_left_to_fill_out = total_adults;
            for (var i=1; i<=10; i++) {
                $('#adult'+i).hide();
            }
            for (var i=1; i<=total_adults; i++) {
                $('#adult'+i).show();
            }
        }
    },

    'step3_i2': {
        type        : 'dialogue',
        text        : "...",
        emote       : 'question',
        dynamicText: function(){
            return "You said there are "+Game.adults_left_to_fill_out+" adults and "+Object.keys(Game.formData.children).length+" children in your household, is this correct?";
        },
        goTo        : 'step3_i3'
    },

    'step3_i3': {
        type    : 'choice',
        emote       : 'question',
        choices : [
            {
                label       : 'Yes',
                goTo        : 'step3_i4'
            },

            {
                label       : 'No',
                goTo        : 'step3_i1',
            }
        ]
    },


    'step3_i4': {
        type        : 'dialogue',
        text        : "Excellent! I created avatars to represent each adult. Continue by talking to them!",
        emote       : 'happiness',
        end         : true
    },

    'dadult01': {
        type        : 'dialogue',
        emote       : 'question',
        text        : "I'm an avatar representing an adult in your family! Help fill out more information about me.",
        goTo        : 'dadult02'
    },

    'dadult02': {
        type    : 'input',
        goTo    : 'dadult03',
        emote       : 'question',
        label : 'What is my name? (First name, last name)',
        action: function(npc, value) {
            var npc_id = npc.data()['npc'].id;
            if (!(npc_id in Game.formData['adults'])) {
                Game.formData['adults'][npc_id] = {};
            }
            Game.formData['adults'][npc_id]['name'] = value;
        }
    },

    'dadult03': {
        type    : 'inputincome',
        goTo    : 'dadult04',
        emote       : 'question',
        label : 'What income do I get from work?',
        action: function(npc, value) {
            if (npc && value) {
                Game.formData['adults'][npc.data()['npc'].id]['work_income'] = value;
            }
        }
    },

    'dadult04': {
        type    : 'inputincome',
        goTo    : 'dadult05',
        emote       : 'question',
        label : 'What income do I get from Public Assistance/Child Support/Alimony?',
        action: function(npc, value) {
            if (npc && value) {
                Game.formData['adults'][npc.data()['npc'].id]['public_assistance_income'] = value;
            }
        }
    },

    'dadult05': {
        type    : 'inputincome',
        goTo    : 'dadult06',
        emote       : 'question',
        label : 'What income do I get from Pensions/Retirement/All Other Sources?',
        action: function(npc, value) {
            if (npc && value) {
                Game.formData['adults'][npc.data()['npc'].id]['pension_income'] = value;
            }
        }
    },

    'dadult06': {
        type        : 'dialogue',
        text        : "Thanks! I'm good to go!",
        emote       : 'question',
        end         : true,
        triggeredText: function(npc) {
            npc.dialogueId = "step1_start";
        },
        action      : function(npc) {
            if (npc) {
                Game.adults_left_to_fill_out -= 1;
                var move_directions = [];

                move_directions.push('down');
                move_directions.push('down');

                move_directions.push('down');
                move_directions.push('down');
                move_directions.push('down');

                npc.npc('move', move_directions);

                setTimeout(function(){
                    npc.find('.npc-sprite').removeClass('down').addClass('up');
                }, 2000);

                if (Game.adults_left_to_fill_out <= 0) {
                    setTimeout(function(){
                        var newDialogue = Dialogue["step4_npcstart"];
                        $('#n005').npc('talk', newDialogue);
                        $('#n005').data('npc').dialogueId = "step4_start";
                    }, 1000);
                }
            }
        }
    },

    'step4_npcstart': {
        type        : 'dialogue',
        text        : "One last step remains! Go back to the lobby, and then join me in the final room on the left to complete it!",
        emote       : 'happiness',
        end         : true,
        action      : function(npc) {
            if (npc && !npc.data().npc['frozen']) {
                npc.data().npc['frozen'] = true;
                var move_directions = [];

                move_directions.push('left');
                move_directions.push('left');
                move_directions.push('up');

                npc.npc('move', move_directions);

                setTimeout(function(){
                    npc.find('.npc-sprite').removeClass('up').addClass('down');
                }, 2000);

                setTimeout(function(){
                    npc.npc('emote', 'question');
                }, 500);
            }
        }
    },

    'step4_start': {
        type        : 'dialogue',
        emote       : 'question',
        text        : "To finalize the form, we'll need a signature and some contact information. Let's go through that now.",
        goTo        : 'step4_form1a'
    },

    'step4_form1a': {
        type    : 'choice',
        emote       : 'question',
        choices : [
            {
                label       : 'I have a SSN.',
                goTo        : 'step4_form1b'
            },

            {
                label       : 'I do not have a SSN.',
                goTo        : 'step4_form1c'
            }
        ]
    },

    'step4_form1b': {
        type    : 'input',
        emote       : 'question',
        label   : 'What are the last 4 digits of your SSN?',
        goTo    : 'step4_form1c',
        action: function(npc, value) {
            Game.formData['ssn'] = value;
        }
    },


    'step4_form1c': {
        type    : 'input',
        emote       : 'question',
        label   : 'What is your street address?',
        goTo    : 'step4_form2',
        action: function(npc, value) {
            Game.formData['street_address'] = value;
        }
    },

    'step4_form2': {
        type    : 'input',
        emote       : 'question',
        label   : 'City?',
        goTo    : 'step4_form3',
        action: function(npc, value) {
            Game.formData['city'] = value;
        }
    },

    'step4_form3': {
        type    : 'input',
        emote       : 'question',
        label   : 'State?',
        goTo    : 'step4_form4',
        action: function(npc, value) {
            Game.formData['state'] = value;
        }
    },

    'step4_form4': {
        type    : 'input',
        emote       : 'question',
        label   : 'Zip Code?',
        goTo    : 'step4_form5',
        action: function(npc, value) {
            Game.formData['zip'] = value;
        }
    },

    'step4_form5': {
        type    : 'inputoptional',
        emote       : 'question',
        label   : 'Phone number? (optional, hit enter to skip)',
        goTo    : 'step4_form6',
        action: function(npc, value) {
            Game.formData['phonenumber'] = value;
        }
    },

    'step4_form6': {
        type    : 'inputoptional',
        emote       : 'question',
        label   : 'Email? (optional, hit enter to skip)',
        goTo    : 'step4_form7',
        action: function(npc, value) {
            Game.formData['email'] = value;
        }
    },

    'step4_form7': {
        type    : 'input',
        emote       : 'question',
        label   : 'What is your name?',
        goTo    : 'step4_form8a',
        action: function(npc, value) {
            Game.formData['printedname'] = value;
        }
    },

    'step4_form8a': {
        type    : 'dialogue',
        emote       : 'question',
        text   : 'I certify (promise) that all information on this application is true and that all income is reported. I understand that this information is given in connection with the receipt of Federal funds, and that school officials may verify (check) the information.',
        goTo    : 'step4_form8b'
    },

    'step4_form8b': {
        type    : 'dialogue',
        emote       : 'question',
        text   : 'I am aware that if I purposely give false information, my children may lose meal benefits, and I may be prosecuted under applicable State and Federal laws.',
        goTo    : 'step4_form9'
    },

    'step4_form9': {
        type    : 'input',
        emote       : 'question',
        label   : 'Type in your name here, this will operate as your legal signature:',
        goTo    : 'step4_form10a',
        action: function(npc, value) {
            Game.formData['signature'] = value;
        }
    },

    'step4_form10a': {
        type    : 'dialogue',
        emote       : 'question',
        text   : "We are required to ask for information about your children's race and ethnicity. This information is important and helps to make sure we are fully serving our community.",
        goTo    : 'step4_form10b'
    },

    'step4_form10b': {
        type    : 'dialogue',
        emote       : 'question',
        text   : "Responding to this section is optional and does not affect your children's eligibility for free or reduced price meals.",
        goTo    : 'step4_form11'
    },

    'step4_form11': {
        type    : 'choice',
        emote       : 'question',
        choices : [
            {
                label       : 'I would NOT like to fill out this optional information.',
                goTo        : 'step4_end'
            },
            {
                label       : 'I would like to fill out this optional information.',
                goTo        : 'step4_form12'
            }
        ]
    },

    'step4_form12': {
        type    : 'choice',
        emote       : 'question',
        choices : [
            {
                label       : 'Ethnicity: Not Hispanic or Latino',
                goTo        : 'step4_form13',
                action: function(npc, value) {
                    Game.formData['ethnicity_hispanic'] = false;
                }
            },
            {
                label       : 'Ethnicity: Hispanic or Latino',
                goTo        : 'step4_form13',
                action: function(npc, value) {
                    Game.formData['ethnicity_hispanic'] = true;
                }
            }
        ]
    },

    'step4_form13': {
        type    : 'choice',
        emote       : 'question',
        choices : [
            {
                label       : 'Race: NOT American Indian or Alaskan Native',
                goTo        : 'step4_form14',
                action: function(npc, value) {
                    Game.formData['race_american_indian'] = false;
                }
            },
            {
                label       : 'Race: American Indian or Alaskan Native',
                goTo        : 'step4_form14',
                action: function(npc, value) {
                    Game.formData['race_american_indian'] = true;
                }
            }
        ]
    },

    'step4_form14': {
        type    : 'choice',
        emote       : 'question',
        choices : [
            {
                label       : 'Race: NOT Asian',
                goTo        : 'step4_form15',
                action: function(npc, value) {
                    Game.formData['race_asian'] = false;
                }
            },
            {
                label       : 'Race: Asian',
                goTo        : 'step4_form15',
                action: function(npc, value) {
                    Game.formData['race_asian'] = true;
                }
            }
        ]
    },

    'step4_form15': {
        type    : 'choice',
        emote       : 'question',
        choices : [
            {
                label       : 'Race: NOT Black or African American',
                goTo        : 'step4_form16',
                action: function(npc, value) {
                    Game.formData['race_black'] = false;
                }
            },
            {
                label       : 'Race: Black or African American',
                goTo        : 'step4_form16',
                action: function(npc, value) {
                    Game.formData['race_black'] = true;
                }
            }
        ]
    },

    'step4_form16': {
        type    : 'choice',
        emote       : 'question',
        choices : [
            {
                label       : 'Race: NOT Native Hawaiian or Other Pacific Islander',
                goTo        : 'step4_form17',
                action: function(npc, value) {
                    Game.formData['race_hawaiian'] = false;
                }
            },
            {
                label       : 'Race: Native Hawaiian or Other Pacific Islander',
                goTo        : 'step4_form17',
                action: function(npc, value) {
                    Game.formData['race_hawaiian'] = true;
                }
            }
        ]
    },

    'step4_form17': {
        type    : 'choice',
        emote       : 'question',
        choices : [
            {
                label       : 'Race: NOT White',
                goTo        : 'step4_end',
                action: function(npc, value) {
                    Game.formData['race_white'] = false;
                }
            },
            {
                label       : 'Race: White',
                goTo        : 'step4_end',
                action: function(npc, value) {
                    Game.formData['race_white'] = true;
                }
            }
        ]
    },

    'step4_end': {
        type        : 'dialogue',
        text        : "Excellent! We're all done!",
        emote       : 'happiness',
        end         : true,
        action: function(npc, value) {
            if (!Game.formsub) {
                Game.formsub = true;
                submit_form();
            }
        }
    },
}


/** GAME ******************************************************************************************/

Game = {
    activeNPC          : '',
    npcDialogueProgress: {},
    formData: {
        'children': {},
        'adults': {}
    },
    currentArea        : 'a000',
    currentDirection   : 'down',
    currentFocus       : '',
    domain             : location.protocol + '//' + location.host + '/static/pub/',
    directions         : {
        up      : 'up',
        down    : 'down',
        left    : 'left',
        right   : 'right'
    },
    fps                : 60,
    gridCellSize       : 32,
    loading            : 0,
    preloading         : false,
    pressedKeys        : [],
    prevArea           : 'a000',

    /**
     *
     */
    calculateZindex : function (object) {
        object.css({
            zIndex: object.position().top
        });
    },

    /**
     *
     */
    checkCollisions : function (object, direction) {
        var
            objectCoord = Game.getCoordinates(object),
            offsetL     = 0,
            offsetT     = 0;

        switch (direction) {

            // Up
            case Game.directions.up:
                offsetT = -1;

                break;

            // Down
            case Game.directions.down:
                offsetT = 1;

                break;

            // Left
            case Game.directions.left:
                offsetL = -1;

                break;

            // Right
            case Game.directions.right:
                offsetL = 1;

                break;
        }

        if (Stage.collisionsMap[objectCoord.y + offsetT]) {
            if (Stage.collisionsMap[objectCoord.y + offsetT][objectCoord.x + offsetL]) {
                return Stage.collisionsMap[objectCoord.y + offsetT][objectCoord.x + offsetL];
            }
        }

        if (Stage.portalsMap[objectCoord.y + offsetT]) {
            if (Stage.portalsMap[objectCoord.y + offsetT][objectCoord.x + offsetL]) {
                return Stage.portalsMap[objectCoord.y + offsetT][objectCoord.x + offsetL];
            }
        }

        if (Stage.npcsMap[objectCoord.y + offsetT]) {
            if (Stage.npcsMap[objectCoord.y + offsetT][objectCoord.x + offsetL]) {
                return Stage.npcsMap[objectCoord.y + offsetT][objectCoord.x + offsetL];
            }
        }

        //if (Stage.playersMap[objectCoord.y + offsetT]) {
        //    if (Stage.playersMap[objectCoord.y + offsetT][objectCoord.x + offsetL]) {
        //        return Stage.playersMap[objectCoord.y + offsetT][objectCoord.x + offsetL];
        //    }
        //}

        return false;
    },

    /**
     *
     */
    getCoordinates : function (object) {
        var objectPos = object.position();

        return {
            'x': objectPos.left / Game.gridCellSize,
            'y': objectPos.top / Game.gridCellSize
        }
    },

    /**
     *
     */
    moveObject : function (object, direction, callback) {
        var
            animateOptions  = {},
            objectPos       = object.position(),
            left            = objectPos.left,
            top             = objectPos.top;

        switch (direction) {

            // Up
            case Game.directions.up:
                animateOptions = {
                    top: top - Game.gridCellSize
                }

                break;

            // Down
            case Game.directions.down:
                animateOptions = {
                    top: top + Game.gridCellSize
                }

                break;

            // Left
            case Game.directions.left:
                animateOptions = {
                    left: left - Game.gridCellSize
                }

                break;

            // Right
            case Game.directions.right:
                animateOptions = {
                    left: left + Game.gridCellSize
                }

                break;

        }

        object.stop().animate(
            animateOptions,
            180,
            'linear',
            function () {
                Game.calculateZindex(object);

                if (callback) {
                    callback();
                }
            }
        );
    },

    /**
     *
     */
    preload : function () {
        var preload = [
                // Tile Map
                '/static/pub/img/tile-map.gif',

                // Player
                '/static/pub/img/rene-down.gif',
                '/static/pub/img/rene-down-walking.gif',
                '/static/pub/img/rene-left.gif',
                '/static/pub/img/rene-left-walking.gif',
                '/static/pub/img/rene-up.gif',
                '/static/pub/img/rene-up-walking.gif',

                // NPC
                '/static/pub/img/dude.gif',

                // Modals
                '/static/pub/img/modal-border.gif',

                // Emotes
                '/static/pub/img/emote-happiness.gif',
                '/static/pub/img/emote-love.gif',
                '/static/pub/img/emote-question.gif',
                '/static/pub/img/emote-sadness.gif',
                '/static/pub/img/emote-talk-angry.gif',
                '/static/pub/img/emote-talk-happy.gif',
                '/static/pub/img/emote-think.gif',

                // Icons
                '/static/pub/img/icon-continue.gif'
            ],
            outstanding = preload.length;

        Game.preloading = true;

        if ($('#loading').length == 0) {
            $('body').append('<div id="loading">Loading...</div>');
        }

        $.each(preload, function (index, value) {
            Game.loading = true;

            $.ajax({
                type    : 'GET',
                url     : value
            }).done(function () {
                // Do nothing
            }).fail(function () {
                // Do nothing
            }).always(function () {
                outstanding--;

                if (outstanding === 0) {
                    Game.loading = false;

                    Game.start();
                }
            });
        });
    },

    /**
     *
     */
    start : function () {
        setInterval(function () {
            Game.update();
        }, 1000 / Game.fps);

        Stage.init('a000');
    },

    /**
     *
     */
    update : function () {
        if (Game.loading) {
            if ($('#loading').length == 0) {
                $('body').append('<div id="loading">Loading...</div>');
            }
        } else {
            $('#loading').remove();
        }

        if ($('.modal').length > 0) {
            $.modals.checkButtons();
        }

        if ($('#player').length > 0) {
            $.player.checkButtons();
        }

        Stage.checkButtons();
    }
};

/** BINDINGS **************************************************************************************/

var game_keys = [38,37,39,40,32,13]; //Arrow keys, spacebar, enter
$(document).on('keydown', function (event) {
    var key = event.keyCode || event.which;
    if (key in game_keys) {
        event.preventDefault();
    }
    Game.pressedKeys[event.keyCode] = true;
});

$(document).on('keyup', function (event) {

    var key = event.keyCode || event.which;
    if (key in game_keys) {
        event.preventDefault();
    }
    Game.pressedKeys[event.keyCode]     = false;
    $.modals.allowPress                 = true;
    $.player.allowPress                 = true;
});

function trigger_beginning() {
    var newDialogue = Dialogue[$('#n002').data('npc')['dialogueId']];
    if ('triggeredText' in newDialogue) {
        newDialogue.triggeredText($('#n002').data('npc'));
    }
    $('#n002').npc('talk', newDialogue);

    //$.modals.create(
    //    {
    //        height  : 16,
    //        width   : '25%'
    //    },
    //    {
    //        left    : 20 + 3, // The 3 is half the border-image-outset value
    //        top     : $(window).height() - 68 - 3 // The 3 is half the border-image-outset value
    //    },
    //    Dialogue['help1']
    //);
}

/** GAME START! ***********************************************************************************/

//
$(document).on('ready', function () {
    Game.preload();
});


/** MODAL WINDOWS *********************************************************************************/

function Modals () {
    this.activeModal    = '';
    this.allowPress     = true;
    this.cancelTyping   = false;
    this.continueIcon   = '<div class="icon continue"></div>'
    this.id             = 0;
    this.modalCounter   = 0;
    this.npc            = '';
    this.typing         = false;

    /**
     *
     */
    this.checkButtons = function () {
        var modal = $.modals.activeModal;

        if (modal.length == 0 || modal.html() == '') {
            return;
        }

        var
            activeElement   = $(document.activeElement),
            dialogue        = modal.data('modal')['dialogue'];

        if (!$.modals.allowPress) {
            return;
        }
        
        // Spacebar, Enter
        if (Game.pressedKeys[13] || Game.pressedKeys[32]) {
            $.modals.allowPress = false;

            switch (true) {
                case (activeElement.is('li')) :
                    if (Game.pressedKeys[13]) { //enter key only
                        var choice = dialogue.choices[activeElement.index()];
                        if (choice.action) {
                            choice.action(modal.data('modal')['npc'], choice);
                        }

                        if (choice.goTo) {
                            return modal.modal('populate', Dialogue[choice.goTo]);
                        }

                    }
                    break;

                case (activeElement.is('input') || activeElement.hasClass('inputincome')) :
                    if (Game.pressedKeys[13]) { //enter key only

                        var value = activeElement.val();

                        if (activeElement.hasClass('inputincome')) {
                            value = activeElement.parent().find('input').val() + " " + activeElement.parent().find('select').val();
                        }

                        if (activeElement.hasClass('inputoptional') || value) {
                            if (dialogue.action) {
                                dialogue.action(modal.data('modal')['npc'], value);
                            }

                            if (dialogue.goTo) {
                                return modal.modal('populate', Dialogue[dialogue.goTo]);
                            }
                        }

                    }
                    break;
                
                default :
                    if ($.modals.typing) {
                        $.modals.cancelTyping = true;

                        return;
                    }

                    if (dialogue.action) {
                        dialogue.action(modal.data('modal')['npc']);
                    }

                    if (dialogue.goTo) {
                        modal.modal('populate', Dialogue[dialogue.goTo]);

                        break;
                    } else if (dialogue.end) {
                        modal.modal('destroy', $('#player'));

                        if (modal.data('modal')['npc']) {
                            modal.data('modal')['npc'].data('npc')['wanderPause'] = false;
                        }

                        break;
                    }

                    break;
            }
        }

        switch (true) {

            // Up Arrow
            case ((Game.pressedKeys[38])) :
                $.modals.allowPress = false;

                switch (true) {
                    case (activeElement.is('li')) :
                        activeElement.prev('li').trigger('focus');

                        break;
                }

                break;

            // Down Arrow
            case ((Game.pressedKeys[40])) :
                $.modals.allowPress = false;

                switch (true) {
                    case (activeElement.is('li')) :
                        activeElement.next('li').trigger('focus');

                        break;
                }

                break;

            // Left Arrow
            case ((Game.pressedKeys[37])) :
                $.modals.allowPress = false;

                break;

            // Right Arrow
            case ((Game.pressedKeys[39])) :
                $.modals.allowPress = false;

                break;

            default:

                break;
        }
    }

    /**
     *
     */
    this.create = function (size, position, dialogue, npc) {
        var
            delay   = 0,
            modal   = '',
            id      = $.modals.modalCounter + '';

        $.modals.allowPress = false;

        while (id.length < (3 - (($.modals.modalCounter + '')).length + 1)) {
            id = '0' + id;
        }

        id = 'm' + id;

        if (dialogue.type == 'notification') {
            delay = 180;

            $('.modal.notification').not(modal).each(function (index, element) {
                $(element).modal('destroy', null);
            });
        }

        setTimeout(function () {
            $('#modals').append('<div id="' + id + '" class="modal ' + dialogue.type + '" tabindex="0"></div>');

            $.modals.modalCounter++;

            modal = $('#' + id);

            modal.data('modal', new Modals());
            modal.data('modal')['id']   = id;

            if (npc) {
                modal.data('modal')['npc']  = npc ? npc : '';
            }

            modal.css({
                left    : position.left,
                top     : position.top
            });

            modal.animate({
                height  : size.height,
                width   : size.width
            }, 180, function () {
                modal.modal('populate', dialogue);

                $.modals.activeModal = modal;
            });
        }, delay);
    },

    /**
     *
     */
    this.destroy = function (focus) {
        var
            modal   = $(this),
            npc     = modal.data('modal')['npc'];

        modal.html('');

        modal.animate({
            height  : 0,
            width   : 0,
            zIndex  : 0
        }, 180, function () {
            modal.remove();

            if (npc) {
                npc.npc('destroyEmote');

                $.npc.talking = false;
            }

            if (focus) {
                focus.trigger('focus');
            }
        });
    },

    /**
     *
     */
    this.option = function (option, value) {
        var
            element = $(this),
            data    = element.data('modal');

        if (typeof value === 'undefined') {
            return data[option];
        } else {
            data[option] = value;

            switch (option) {

            }
        }
    },

    /**
     *
     */
    this.populate = function (dialogue) {
        var
            emote   = dialogue.emote,
            modal   = $(this),
            npc     = Game.activeNPC,
            type    = dialogue.type;

        if (npc && emote) {
            npc.npc('emote', emote);
        }

        if ('dynamicText' in dialogue) {
            dialogue.text = dialogue.dynamicText(Game.activeNPC);
        }

        if ('dynamicLabel' in dialogue) {
            dialogue.label = dialogue.dynamicLabel(Game.activeNPC);
        }

        modal.data('modal')['dialogue'] = dialogue;

        switch (type) {

            // Choice
            case 'choice':
                var choices = '<ul class="choice">';

                $.each(dialogue.choices, function (index, value) {
                    if ('dynamicLabel' in value) {
                        value.label = value.dynamicLabel(Game.activeNPC);
                    }
                    choices += '<li tabindex="0">' + value.label + '</li>'
                });

                choices += '</ul>';

                modal.html(choices).find('li:first').trigger('focus');

                break;

            // Input
            case 'input':
                var choices = dialogue.label + '<br><input type="text" tabindex="0">';
                modal.html(choices).find('input').trigger('focus');
                break;

            // Input
            case 'inputoptional':
                var choices = dialogue.label + '<br><input class="inputoptional" type="text" tabindex="0">';
                modal.html(choices).find('input').trigger('focus');
                break;

            // Input
            case 'inputincome':
                var choices = dialogue.label + '<br>$<input class="inputincome" type="text" tabindex="0"> <select class="inputincome"><option>Weekly</option><option>Bi-Weekly</option><option>2x Month</option><option>Monthly</option></select>';
                modal.html(choices).find('input').trigger('focus');
                break;

            // Dialogue
            case 'dialogue':
                var
                    counter     = 0,
                    interval    = setInterval(function () {
                        if ($.modals.cancelTyping) {
                            modal.append(dialogue.text.substr(counter, dialogue.text.length));

                            $.modals.cancelTyping   = false;
                            $.modals.typing         = false;

                            modal.append($.modals.continueIcon);

                            clearInterval(interval);

                            return;
                        };

                        modal.append(dialogue.text.charAt(counter));

                        Sounds.fx.bip.play();

                        counter++;

                        if (counter >= dialogue.text.length) {
                            $.modals.typing = false;

                            modal.append($.modals.continueIcon);

                            clearInterval(interval);

                            return;
                        }
                    }, 50);

                $.modals.typing = true;

                modal.html('');

                //if (dialogue.action) {
                //    dialogue.action(modal.data('modal')['npc']);
                //}

                break;

            // Notification
            case 'notification':
                modal.append(dialogue.text);

                setTimeout(function () {
                    modal.modal('destroy', null);
                }, 10000);

                break;

        }
    }
}

$.fn.modal = function (option) {
    var
        element     = $(this[0]),
        otherArgs   = Array.prototype.slice.call(arguments, 1);

    if (typeof option !== 'undefined' && otherArgs.length > 0) {
        return element.data('modal')[option].apply(this[0], [].concat(otherArgs));
    }

    return element.data('modal');
}

$.modals = new Modals();


/** NPCS ******************************************************************************************/

function NPC () {
    this.dialogueId     = 'd000';
    this.id             = 0;
    this.talking        = false;
    this.wanderInterval = '';
    this.wanderPause    = false;

    /**
     *
     */
    this.create = function (data) {
        var npc;

        $('#objects').append('<div id="' + data.name + '" class="npc"><div class="npc-sprite"></div></div>');

        npc = $('#' + data.name);

        npc.data('npc', new NPC());

        npc.data('npc')['id']           = data.name;
        npc.data('npc')['dialogueId']   = data.properties.dialogue;

        npc.css({
            left    : data.x + 'px',
            top     : (data.y - Game.gridCellSize) + 'px'
        });

        if (!Stage.npcsMap[(data.y / Game.gridCellSize) - 1]) {
            Stage.npcsMap[(data.y / Game.gridCellSize) - 1] = {};
        }

        Stage.npcsMap[(data.y / Game.gridCellSize) - 1][(data.x / Game.gridCellSize)] = npc;

        if (data.properties.wander && data.properties.wander != "false") {
            npc.npc('wander');
        }

        if (data.properties.active && data.properties.active == 'false') {
            $('#'+data.name).hide();
        }

        if (data.properties.defaultdirection) {
            $('#'+data.name).find('.npc-sprite').addClass(data.properties.defaultdirection);
        }

    },

    /**
     *
     */
    this.destroy = function () {
        var npc = $(this);

        clearInterval(npc.data('npc')['wanderInterval']);

        npc.remove();
    }

    /**
     *
     */
    this.destroyEmote = function () {
        var npc = $(this);

        npc.find('.emote').animate({
            opacity : 0,
            top     : '-48px'
        }, 100, function () {
            $(this).remove();
        });
    }

    /**
     *
     */
    this.emote = function (emotion) {
        var
            npc     = $(this),
            emote   = npc.find('.emote');

        if (emote.length === 0) {
            npc.append('<div class="emote ' + emotion + '" style="opacity: 0; top: -48px"></div>');

            npc.find('.emote').animate({
                opacity : 1,
                top     : '-32px'
            }, 100);
        } else {
            npc.find('.emote').replaceWith('<div class="emote ' + emotion + '"></div>');
        }
    },

    /**
     *
     */
    this.move = function (direction) {

        //moving single space
        var direction_single = direction;
        if (typeof direction != "string") {
            direction_single = direction.shift();
        }

        var
            npc         = $(this),
            collision   = Game.checkCollisions(npc, direction_single),
            npcPos      = Game.getCoordinates(npc),
            npcSprite   = npc.find('.npc-sprite');

        Game.currentDirection = direction_single;

        npcSprite.removeClass('walking up down left right').addClass('walking ' + direction_single);

        if (collision) {
            npcSprite.removeClass('walking');
        } else {
            Game.moveObject(npc, direction_single, function () {
                var newPos = Game.getCoordinates(npc);

                if (!Stage.npcsMap[newPos.y]) {
                    Stage.npcsMap[newPos.y] = {};
                }

                Stage.npcsMap[newPos.y][newPos.x] = npc;

                delete Stage.npcsMap[npcPos.y][npcPos.x];

                npcSprite.removeClass('walking');
                if (typeof direction != "string" && direction.length > 0) {
                    Game.activeNPC.npc('move', direction);
                }
            });
        }

    },

    /**
     *
     */
    this.talk = function (dialogue) {
        var npc = $(this);

        if ($.npc.talking) {
            return;
        }

        $.npc.talking                   = true;
        npc.data('npc')['wanderPause']  = true;

        Game.activeNPC = npc;

        $.modals.create(
            {
                height  : 80,
                width   : 720
            },
            {
                left    : ($(window).width() - (720 + Game.gridCellSize)) / 2,
                top     : 20
            },
            dialogue,
            npc
        );
    },

    /**
     *
     */
    this.wander = function () {
        var npc = $(this);

        clearInterval(npc.data('npc')['wanderInterval']);

        npc.data('npc')['wanderInterval'] = setInterval(function () {
            var
                direction = Game.directions[Object.keys(Game.directions)[Math.floor(Math.random() * Object.keys(Game.directions).length)]];

            if (Math.random() < 0.5 || npc.data('npc')['wanderPause'] === true) {
                return;
            }

            npc.npc('move', direction);

        }, 1800);
    }
}

$.fn.npc = function (option) {
    var
        element     = $(this[0]),
        otherArgs   = Array.prototype.slice.call(arguments, 1);

    if (typeof option !== 'undefined' && otherArgs.length > 0) {
        return element.data('npc')[option].apply(this[0], [].concat(otherArgs));
    } else if (typeof option !== 'undefined') {
        return element.data('npc')[option].call (this[0]);
    } else {
        return element.data('npc');
    }
}

$.npc = new NPC();


/** PLAYER ****************************************************************************************/

function Player () {
    this.allowMove          = true;
    this.allowPress         = true;
    this.direction          = null;
    this.speedMultiplier    = 1;

    /**
     *
     */
    this.checkButtons = function () {
        var player = $('#player');

        if (player.length == 0) {
            return;
        }

        var
            allowMove       = player.data('player')['allowMove'],
            allowPress      = $.player.allowPress;
            playerSprite    = $('#player-sprite');

        if (!allowPress) {
            return;
        }

        player.data('player')['speedMultiplier'] = 1;

        // Spacebar, Enter
        if (Game.pressedKeys[13] || Game.pressedKeys[32]) {
            var collision = Game.checkCollisions(player, player.data('player')['direction']);

            $.player.allowPress = false;

            if (collision) {
                switch (true) {
                    case (collision) :
                        // Do nothing

                        break;

                    case (collision.is('.npc')) :
                        var newDialogue = Dialogue[collision.data('npc')['dialogueId']];
                        if ('triggeredText' in newDialogue) {
                            newDialogue.triggeredText(collision.data('npc'));
                        }
                        collision.npc('talk', newDialogue);
                        break;
                }
            }
        }


        switch (true) {

            // Up Arrow
            case (Game.pressedKeys[38]) :
                if (!$('.modal').length) {
                    var direction = player.data('player')['direction'] = Game.directions.up;
                    player.player('move', direction);
                }

                break;

            // Down Arrow
            case (Game.pressedKeys[40]) :
                if (!$('.modal').length) {
                    var direction = player.data('player')['direction'] = Game.directions.down;
                    player.player('move', direction);
                }

                break;

            // Left Arrow
            case (Game.pressedKeys[37]) :
                if (!$('.modal').length) {
                    var direction = player.data('player')['direction'] = Game.directions.left;
                    player.player('move', direction);
                }

                break;

            // Right Arrow
            case (Game.pressedKeys[39]) :
                if (!$('.modal').length) {
                    var direction = player.data('player')['direction'] = Game.directions.right;
                    player.player('move', direction);
                }

                break;

            default:
                playerSprite.removeClass('walking');

                break;
        }
    }

    /**
     *
     */
    this.create = function (data) {
        var player;

        if (data.properties.prevArea === Game.prevArea) {
            $('#objects').append('<div id="player" style="left: ' + data.x + 'px; top: ' + (data.y - 32) + 'px;"><div id="player-sprite" class="' + Game.currentDirection + '"></div></div>');

            player = $('#player');

            player.data('player', new Player());

            if (!Stage.playersMap[(data.y / Game.gridCellSize) - 1]) {
                Stage.playersMap[(data.y / Game.gridCellSize) - 1] = {};
            }

            Stage.playersMap[(data.y / Game.gridCellSize) - 1][(data.x / Game.gridCellSize)] = player;
        }
    }

    /**
     *
     */
    this.destroy = function () {
        var player = $(this);

        player.remove();
    }

    /**
     *
     */
    this.move = function (direction, callback) {
        var
            player          = $(this),
            playerPos       = Game.getCoordinates(player);
            playerSprite    = $('#player-sprite');

        if (player.data('player')['allowMove']) {
            var collision = Game.checkCollisions(player, direction);

            Game.currentDirection = direction;

            playerSprite.removeClass().addClass('walking ' + direction);

            if (collision) {
                switch (true) {

                    // Not Doorway or Stairs
                    case (collision) :
                        playerSprite.removeClass('walking');

                        Sounds.fx.bump.play();

                        break;

                    // Doorway
                    case (collision.is('.doorway')) :
                        player.data('player')['allowMove'] = false;

                        Sounds.fx.door.play();

                        Game.moveObject(player, direction, function () {
                            var newPos = Game.getCoordinates(player);

                            if (!Stage.playersMap[newPos.y]) {
                                Stage.playersMap[newPos.y] = {};
                            }

                            Stage.playersMap[newPos.y][newPos.x] = player;

                            Sounds.fx.enter.play();

                            delete Stage.playersMap[playerPos.y][playerPos.x];

                            Stage.init(collision.attr('data-area'));
                        });

                        break;

                    // Stairs
                    case (collision.is('.stairs')) :
                        player.data('player')['allowMove'] = false;

                        Sounds.fx.enter.play();

                        player.player('useStairs', collision.attr('data-direction'), function () {
                            Stage.init(collision.attr('data-area'));
                        });

                        break;
                }
            } else {
                player.data('player')['allowMove'] = false;

                Game.moveObject(player, direction, function () {
                    var newPos = Game.getCoordinates(player);

                    player.data('player')['allowMove'] = true;

                    if (!Stage.playersMap[newPos.y]) {
                        Stage.playersMap[newPos.y] = {};
                    }

                    Stage.playersMap[newPos.y][newPos.x] = player;

                    delete Stage.playersMap[playerPos.y][playerPos.x];
                });

                Stage.scrollStage(direction);
            }
        }
    }

    /**
     *
     */
    this.useStairs = function (direction, callback) {
        var
            player      = $(this),
            playerPos   = player.position(),
            offsetL     = 0,
            offsetT     = 0;

        switch (direction) {

            // Down & Left
            case 'dl':
                offsetL = -32;
                offsetT = 0; // Player clips through the stairs if set to 32

                break;

            // Down & Right
            case 'dr':
                offsetL = 32;
                offsetT = 32;

                break;

            // Up & Left
            case 'ul':
                offsetL = -32;
                offsetT = -32;

                break;

            // Up & Right
            case 'ur':
                offsetL = 32;
                offsetT = -32;

                break;
        }

        player.addClass('walking').stop().animate({
            left    : playerPos.left + offsetL,
            top     : playerPos.top + offsetT
        }, 180, 'linear', function () {
            if (callback) {
                callback();
            }
        });
    }
}

$.fn.player = function (option) {
    var
        element     = $(this[0]),
        otherArgs   = Array.prototype.slice.call(arguments, 1);

    if (typeof option !== 'undefined' && otherArgs.length > 0) {
        return element.data('player')[option].apply(this[0], [].concat(otherArgs));
    } else if (typeof option !== 'undefined') {
        return element.data('player')[option].call (this[0]);
    } else {
        return element.data('player');
    }
}

$.player = new Player();


/** SOUNDS ****************************************************************************************/

Sounds = {
    currentMusic   : '',
    currentMusicId : '',
    fx             : {
        bip     : new Audio(Game.domain + '/sounds/bip.wav'),
        bump    : new Audio(Game.domain + '/sounds/bump.wav'),
        door    : new Audio(Game.domain + '/sounds/door.wav'),
        enter   : new Audio(Game.domain + '/sounds/enter.wav'),
        error   : new Audio(Game.domain + '/sounds/error.wav')
    },
    music          : {
        //shadesOfRed : Game.domain + '/sounds/Pokemon_Red_Version_Shades_of_Red_OC_ReMix.mp3',
        //wetDreams   : Game.domain + '/sounds/Pokemon_Blue_Version_Wet_Dreams_OC_ReMix.mp3'
    },

    changeMusic : function (newMusic) {
        if (Sounds.currentMusic) {
            Sounds.fade(Sounds.currentMusic, 0, function () {
                Sounds.currentMusic.pause();
            });
        }

        Game.loading = true;

        Sounds.currentMusic   = new Audio(newMusic);

        Sounds.currentMusic.canplaythrough = Sounds.playMusic();
    },

    fade : function (sound, volume, callback) {
        var
            offset  = 0.0001,
            steps   = Math.abs(sound.volume - volume) / 0.0001;

        if (sound.volume > volume) {
            offset = -0.0001;
        }

        for (var i = 1; i <= steps; i++) {
            sound.volume += offset;
        }

        if (callback) {
            callback();
        }
    },

    playMusic : function () {
        Game.loading = false;

        Sounds.currentMusic.loop = true;

        Sounds.currentMusic.play();

        $.modals.create(
            {
                height  : 16,
                width   : '25%'
            },
            {
                left    : 20 + 3, // The 3 is half the border-image-outset value
                top     : $(window).height() - 68 - 3 // The 3 is half the border-image-outset value
            },
            Dialogue[Sounds.currentMusicId]
        );
    }
}


/** STAGE *****************************************************************************************/

Stage = {
    collisionsMap  : [],
    height         : 0,
    npcsMap        : [],
    playersMap     : [],
    portalsMap     : [],
    tileMap        : {
        height  : 50,
        width   : 50
    },
    width          : 0,

    /**
     *
     */
    center : function () {
        var
            left        = 0,
            player      = $('#player'),
            playerPos   = player.position(),
            stage       = $('#stage'),
            top         = 0,
            windowH     = $(window).height(),
            windowW     = $(window).width();

        left    = (windowW / 2) - (playerPos.left + (player.width() / 2));
        top     = (windowH / 2) - (playerPos.top + ((player.height() + 8)/ 2));

        if (Stage.width <= windowW && Stage.height <= windowH) {
            left    = (windowW - Stage.width) / 2;
            top     = (windowH - Stage.height) / 2;
        }

        if (Stage.width > windowW && stage.offset().left > 0 && playerPos.left < windowW
            && Stage.height > windowH && stage.offset().top > 0 && playerPos.top < windowH) {
            left    = 0;
            top     = 0;
        }

        stage.css({
            height  : Stage.height,
            left    : left + 'px',
            top     : top + 'px',
            width   : Stage.width
        });
    },

    /**
     *
     */
    checkButtons : function () {
        // Shift
        if (Game.pressedKeys[16]) {

        }

        // Spacebar, Enter
        if (Game.pressedKeys[13] || Game.pressedKeys[32]) {

        }

        switch (true) {

            // W, Up Arrow
            case ((Game.pressedKeys[87] || Game.pressedKeys[38])) :

                break;

            // S, Down Arrow
            case ((Game.pressedKeys[83] || Game.pressedKeys[40])) :

                break;

            // A, Left Arrow
            case ((Game.pressedKeys[65] || Game.pressedKeys[37])) :

                break;

            // D, Right Arrow
            case ((Game.pressedKeys[68] || Game.pressedKeys[39])) :

                break;

            default:

                break;
        }
    },

    /**
     *
     */
    cleanup : function () {
        Stage.collisionsMap   = [];
        Stage.npcsMap         = [];
        Stage.playersMap      = [];
        Stage.portalsMap      = [];

        $('.npc').each(function (index, element) {
            $(element).npc('destroy');
        });

        $('#player').each(function (index, element) {
            $(element).player('destroy');
        });

        $('#collisions').html('');
        // $('#modals').html('');
        $('#objects').html('');
        $('#tiles').html('');

        $(document).trigger('keyup');
    },

    /**
     *
     */
    drawCollisions : function (collisions) {
        var
            counter = 0,
            height  = collisions.height,
            row     = 0,
            width   = collisions.width;

        $.each(collisions.data, function (index, value) {
            if (!Stage.collisionsMap[row]) {
                Stage.collisionsMap[row] = {};
            }

            Stage.collisionsMap[row][counter] = (value === 2);

            if (value !== 0) { // 0 is empty, 2 is a collision
                $('#collisions').append(
                    '<div class="collision" '
                    + 'style="left: ' + (counter * Game.gridCellSize) + 'px; top: ' + (row * Game.gridCellSize) + 'px">'
                    + '</div>'
                );
            }

            counter += (index + 1) % width === 0 ? -counter : 1;
            row     += (index + 1) % width === 0 ? 1 : 0;
        });
    },

    /**
     *
     */
    drawObjects : function (objects) {
        $.each(objects.objects, function (index, value) {
            switch (value.type) {
                case 'player':
                    $.player.create(value);

                    break;

                case 'npc':
                    $.npc.create(value);

                    break;

                case 'doorway':
                    $('#objects').append(
                        '<div id="' + value.name + '" '
                        + 'class="object doorway" '
                        + 'data-area="' + value.properties.area + '" '
                        + 'style="left: ' + value.x + 'px; top: ' + (value.y - Game.gridCellSize) + 'px">'
                        + '</div>'
                    );

                    if (!Stage.portalsMap[(value.y / Game.gridCellSize) - 1]) {
                        Stage.portalsMap[(value.y / Game.gridCellSize) - 1] = {};
                    }

                    Stage.portalsMap[(value.y / Game.gridCellSize) - 1][(value.x / Game.gridCellSize)] = $('#' + value.name);

                    break;

                case 'stairs':
                    $('#objects').append(
                        '<div id="' + value.name + '" '
                        + 'class="object stairs" data-area="' + value.properties.area + '" '
                        + 'data-direction="' + value.properties.direction + '" '
                        + 'style="left: ' + value.x + 'px; top: ' + (value.y - Game.gridCellSize) + 'px">'
                        + '</div>'
                    );

                    if (!Stage.portalsMap[(value.y / Game.gridCellSize) - 1]) {
                        Stage.portalsMap[(value.y / Game.gridCellSize) - 1] = {};
                    }

                    Stage.portalsMap[(value.y / Game.gridCellSize) - 1][(value.x / Game.gridCellSize)] = $('#' + value.name);

                    break;
            }
        });
    },

    /**
     *
     */
    drawTiles : function (tiles) {
        var
            counter = 0,
            height  = tiles.height,
            row     = 0,
            width   = tiles.width;

        var yellow_brick_counter = 0;

        $.each(tiles.data, function (index, value) {
            var
                y   = Math.ceil(value / Stage.tileMap.width),
                x   = (value - ((y - 1) * Stage.tileMap.width));

            if (value !== 0) { // 0 is empty, therefore don't draw it
                var yellow_brick_road = "";
                var yellow_brick_counter_display = "";
                if (tiles.name == "tiles2" && value == 4) {
                    yellow_brick_road = " display:none;";
                    yellow_brick_counter += 1;
                    yellow_brick_counter_display = " yb"+yellow_brick_counter;
                }
                $('#tiles').append(
                    '<div class="tile t' + value + ' ' + tiles.name + yellow_brick_counter_display + '" '
                    + 'style="background-position: -' + ((x * Game.gridCellSize) - Game.gridCellSize) + 'px -' + ((y * Game.gridCellSize) - Game.gridCellSize) + 'px; '+ yellow_brick_road
                    + 'left: ' + (counter * Game.gridCellSize) + 'px; top: ' + (row * Game.gridCellSize) + 'px">'
                    + '</div>'
                );
            }

            counter += (index + 1) % width === 0 ? -counter : 1;
            row     += (index + 1) % width === 0 ? 1 : 0;
        });
    },

    /**
     *
     */
    init : function (stage) {
        var transition = $('#transition');

        transition.animate({
            opacity: 1
        }, 180, function () {
            Stage.cleanup();

            Game.loading = true;

            $.ajax({
                // cache       : false, // For development purposes
                dataType    : 'json',
                type        : 'GET',
                url         : '/static/pub/json/'+ stage +'.json',
            }).done(function (data, textStatus, jqXHR) {
                Game.prevArea     = Game.currentArea;
                Game.currentArea  = stage;
                Stage.height      = data.height * Game.gridCellSize;
                Stage.width       = data.width * Game.gridCellSize;

                $.each(data.layers, function (index, value) {
                    var layer = value;

                    switch (true) {

                        // Collisions
                        case (layer.name == 'collisions') :
                            Stage.drawCollisions(layer);

                            break;

                        // Objects
                        case (layer.type == 'objectgroup') :
                            Stage.drawObjects(layer);

                            break;

                        // Tile Layer
                        default :
                            Stage.drawTiles(layer);

                            break;
                    }
                });

                for (i = 0; i < $('#player, .npc, .object, .tiles3').length; i++) {
                    Game.calculateZindex($('#player, .npc, .object, .tiles3').eq(i));
                }

                Stage.center();

                setTimeout(function(){
                    trigger_beginning()
                }, 2500);

                Game.loading = false;

                if (data.properties.music && Sounds.currentMusic.src != Sounds.music[data.properties.music]) {
                    Sounds.currentMusicId = data.properties.music;

                    Sounds.changeMusic(Sounds.music[data.properties.music]);
                }

                Sounds.fade(Sounds.currentMusic, data.properties.musicVol);

                transition.animate({
                    opacity: 0
                }, 180);
            }).fail(function (jqXHR, textStatus, errorThrown) {
                // Do nothing
            }).always(function (data, textStatus, jqXHR) {
                // Do nothing
            });
        });
    },

    scrollStage : function (direction) {
        var
            player      = $('#player'),
            playerOff   = player.offset(),
            offset      = 0,
            scrollArea  = $('#scroll-area'),
            stage       = $('#stage'),
            stagePos    = stage.position(),
            stageL      = stagePos.left,
            stageT      = stagePos.top,
            windowH     = $(window).height(),
            windowW     = $(window).width();

        if ((Stage.width > windowW || Stage.height > windowH)) {
            switch (direction) {

                // Up
                case Game.directions.up:
                    if ((playerOff.top + (Game.gridCellSize / 2)) < (windowH / 2) && stageT < 0) {
                        stage.stop().animate({
                            top: stageT + Game.gridCellSize + offset
                        }, 180, 'linear');
                    }

                    break;

                // Down
                case Game.directions.down:
                    if ((playerOff.top + (Game.gridCellSize / 2)) > (windowH / 2)
                        && Math.abs(stageT - windowH) < Stage.height) {
                        stage.stop().animate({
                            top: stageT - Game.gridCellSize + offset
                        }, 180, 'linear');
                    }

                    break;

                // Left
                case Game.directions.left:
                    if ((playerOff.left + (Game.gridCellSize / 2)) < (windowW / 2) && stageL < 0) {
                        stage.stop().animate({
                            left: stageL + Game.gridCellSize + offset
                        }, 180, 'linear');
                    }

                    break;

                // Right
                case Game.directions.right:
                    if ((playerOff.left + (Game.gridCellSize / 2)) > (windowW / 2)
                        && Math.abs(stageL - windowW) < Stage.width) {
                        stage.stop().animate({
                            left: stageL - Game.gridCellSize + offset
                        }, 180, 'linear');
                    }

                    break;
            }
        }
    }
}
