var sc2builds = [];

$('ul.commands li').live('click', function() {
    window.location = window.location + '.' + $(this).attr('class');
    sc2builds[$(this).parent().attr('class').match(/[0-9]+$/)[0]].process_command($(this).attr('class'));
    sc2builds[$(this).parent().attr('class').match(/[0-9]+$/)[0]].display();
});

(function($) {
    $.fn.sc2build = function(options) {
        var opts = $.extend({}, $.fn.sc2build.defaults, options);
        sc2builds.push(new sc2build(this, opts, sc2builds.length));
    }
    
    $.fn.sc2build.defaults = {
        build : 'p'
    };
    
    //*************************************************************** sc2build
    function sc2build(div, opts, id) {
        this.div = $(div);
        this.id = id;
        var build_order = opts.build.split('.');
        this.race = new race(build_order.shift());
        
        for(var i in this.race.units.init) {
            this.force_unit(this.race.units.init[i]);
        }
        
        var time = 1;
        for(var i in build_order) {
            time = this.process_command(build_order[i], time)
        }
        
        this.display();
    }
    
    sc2build.prototype.display = function() {
        this.div.html('<table><thead><tr><th>Supply</th><th>Minerals</th><th>Action</th><th>Time</th></tr></thead><tbody></tbody></table><ul class="commands '+this.id+'"><li class="a0m">assign probes to minerals</li><li class="a1bA">build nexus</li><li class="a1bB">build pylon</li><li class="a1bC">build gateway</li><li class="A1ba">build probe</li><li class="C1bb">build zealot</li></ul>');
        
        var tbody = this.div.find('tbody');
        
        // set time as 1
        var curr_time = 1;
        // more action is true
        var more_action = true;
        while(more_action) {
        // while more action is true
            // more action is false
            more_action = false;
            // foreach unit
            for(var i in this.units) for (var j in this.units[i]) {
                // foreach status
                for(var k in this.units[i][j].status) {
                    if(this.units[i][j].status[k][0] == curr_time) {
                    // if status time equals time
                        // display action
                        tbody.append($(
                            '<tr>'+
                                '<td>'+this.get_used_supply(curr_time)+' / '+this.get_total_supply(curr_time)+'</td>'+
                                '<td>'+this.get_minerals(curr_time)+'</td>'+
                                '<td>'+this.units[i][j].name+' #'+(Number(j)+1)+' '+this.units[i][j].status[k][1]+'</td>'+
                                '<td>'+curr_time+'</td>'+
                            '</tr>'
                        ));
                    } else if(this.units[i][j].status[k][0] > curr_time) {
                    // elseif status time is greater than time
                        more_action = true;
                    }
                }
            }
            curr_time++;
        }
    }
    
    sc2build.prototype.units = {};
    
    sc2build.prototype.force_unit = function(char) {
        var unit = this.race.get_unit(char);
        if(typeof(this.units[unit.name]) == 'undefined') {
            this.units[unit.name] = [];
        }
        // clone the unit
        new_unit = {};
        for (var i in unit) {
            new_unit[i] = unit[i];
        }
        new_unit.cost.mineral = 0;
        new_unit.status = [[0,'creation'],[0,'available']];
        this.units[unit.name].push(new_unit);
    }
    
    sc2build.prototype.process_command = function(command, time) {
        command = command.match(/^([a-zA-Z])([0-9]+)([a-zA-Z])(.*)$/);
        unit = this.race.get_unit(command[1]);
        var applicable_units;
        if(command[2] == 0) {
            applicable_units = this.units[unit.name];
        } else {
            applicable_units = [this.units[unit.name][command[2]-1]];
        }
        for(var i in applicable_units) {
            var new_time = applicable_units[i].actions[command[3]](
                time, applicable_units[i], this, command[4]
            );
            if(new_time > time) time = new_time;
        }
        return time;
    }
    
    sc2build.prototype.get_availability = function(init_time, unit1, unit2) {
        // find out when the unit is available
        if (unit1.status.length == 0) {
            time = 1;
        } else {
            var last_action = unit1.status[unit1.status.length-1];
            time = last_action[0];
            if(last_action[2] != undefined 
                && last_action[2].cost != undefined 
                && last_action[2].cost.time != undefined) {
                time += last_action[2].cost.time;
            }
        }
        if(time < init_time) time = init_time;
        if(typeof(unit2) == 'undefined') return time;
        while (this.get_minerals(time) < unit2.cost.mineral) {
            time++;
        }
        while (this.get_supply(time) < unit2.cost.supply) {
            time++;
        }
        return time;
    }
    
    sc2build.prototype.get_minerals = function(time) {
        var minerals = 50;
        for(var i in this.race.units) {
            var unit_type = this.race.units[i];
            for(var j in this.units[unit_type.name]) {
                var unit = this.units[unit_type.name][j];
                for (var k in unit.status) {
                    if(unit.status[k][0] > time) continue;
                    switch(unit.status[k][1]) {
                        case 'creation':
                            minerals -= unit.cost.mineral;
                            break;
                        
                        case 'minerals':
                            var harvest_time;
                            if(unit.status[k+1] == undefined) {
                                harvest_time = time - unit.status[k][0];
                            } else {
                                harvest_time = unit.status[k+1][0] - unit.status[k][0];
                            }
                            minerals += unit.mineral_gen / 60 * harvest_time;
                            break;
                    }
                }
            }
        }
        return Math.floor(minerals);
    }
    
    sc2build.prototype.get_supply = function(time) {
        return this.get_total_supply(time) - this.get_used_supply(time);
    }
    
    sc2build.prototype.get_total_supply = function(time) {
        var supply = 0;
        for(var i in this.race.units.supply_producers) {
            var producer = this.race.get_unit(this.race.units.supply_producers[i]);
            for(var j in this.units[producer.name]) {
                var unit = this.units[producer.name][j];
                if(time >= unit.status[1][0]) {
                    supply += Number(unit.supply_gen);
                }
            }
        }
        
        return (supply);
    }
    
    sc2build.prototype.get_used_supply = function(time) {
        var supply = 0;
        for(var i in this.race.units.supply_users) {
            var user = this.race.get_unit(this.race.units.supply_users[i]);
            for(var j in this.units[user.name]) {
                var unit = this.units[user.name][j];
                if(time >= unit.status[0][0]) {
                    supply += Number(unit.cost.supply);
                }
            }
        }
        
        return (supply);
    }
    
    //********************************************************************* race
    function race(id) {
        switch(id) {
            case 'p':
                this.units = this.protoss;
        }
    }
    
    race.prototype.get_unit = function(char) {
        return this.units[char];
    }
    
    race.prototype.protoss = {
        A : {
            name : 'Nexus',
            actions : {
                // produce unit
                b : function(time, unit, build, command) {
                    var availability = build.get_availability(time, unit, build.race.get_unit(command));
                    if(availability === false) return false;
                    var old_unit = build.race.get_unit(command);
                    new_unit = {};
                    for (var i in old_unit) {
                        new_unit[i] = old_unit[i];
                    }
                    new_unit.status = [[
                        availability,
                        'creation',
                    ],[
                        availability + new_unit.cost.time,
                        'available',
                    ]];
                    build.units[old_unit.name].push(new_unit);
                    unit.status.push([availability, 'build', new_unit]);
                    return availability;
                }
            },
            cost : {
                time : 100,
                mineral : 400
            },
            status : [],
            supply_gen : 10
        },
        B : {
            name : 'Pylon',
            cost : {
                time : 35,
                mineral : 100
            },
            status : [],
            supply_gen : 8
        },
        C : {
            name : 'Gateway',
            actions : {
                // produce unit
                b : function(time, unit, build, command) {
                    var availability = build.get_availability(time, unit, build.race.get_unit(command));
                    if(availability === false) return false;
                    var old_unit = build.race.get_unit(command);
                    new_unit = {};
                    for (var i in old_unit) {
                        new_unit[i] = old_unit[i];
                    }
                    new_unit.status = [[
                        availability,
                        'creation',
                    ],[
                        availability + new_unit.cost.time,
                        'available',
                    ]];
                    if(build.units[old_unit.name] == undefined) {
                        build.units[old_unit.name] = [];
                    }
                    build.units[old_unit.name].push(new_unit);
                    unit.status.push([availability, 'build', new_unit]);
                    return availability;
                }
            },
            status : [],
            cost : {
                time : 65,
                mineral : 150
            },
            requirements : ['B'],
            produces : ['b']
        },
        a : {
            name : 'Probe',
            actions : {
                // harvest minerals
                m : function(time, unit, build, command) {
                    var availability = build.get_availability(time, unit);
                    //if(availability == false) return false;
                    unit.status.push([availability, 'minerals']);
                    return availability;
                },
                // warp in building
                b : function(time, unit, build, command) {
                    // find availability
                    var availability = build.get_availability(time, unit, build.race.get_unit(command));
                    if(availability == false) return false;
                    
                    // spawn unit
                    var old_unit = build.race.get_unit(command);
                    new_unit = {};
                    for (var i in old_unit) {
                        new_unit[i] = old_unit[i];
                    }
                    new_unit.status = [[
                        availability,
                        'creation',
                    ],[
                        availability + new_unit.cost.time,
                        'available',
                    ]];
                    
                    // insert unit
                    if(typeof(build.units[old_unit.name]) == 'undefined') {
                        build.units[old_unit.name] = [];
                    }
                    build.units[old_unit.name].push(new_unit);
                    unit.status.push([availability, 'build']);
                    return availability;
                }
            },
            status : [],
            cost : {
                time : 17,
                mineral : 50,
                supply : 1
            },
            requirements : [],
            produces : [
                'A', 'B', 'C'
            ],
            mineral_gen : 20
        },
        b : {
            name : 'Zealot',
            status : [],
            cost : {
                time : 33,
                mineral : 100,
                supply : 2
            }
        },
        supply_producers : ['A','B'],
        supply_users : ['a','b']
    }
    
    race.prototype.protoss.init = [
        'A', 'a', 'a', 'a', 'a', 'a', 'a'
    ]
    
})(jQuery);
