/*
    WiiCade Wii Remote API v2.0 
    Copyright (C) 2007  Jerason Banes

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

    var COMMAND_BUTTONS = 0x01;
    var COMMAND_TWIST = 0x05;
    var COMMAND_DISTANCE = 0x09;
    var COMMAND_FLAGS = 0x0D;
    var COMMAND_ATTACH = 0x0E;
    var COMMAND_CURSORX = 0x12;
    var COMMAND_CURSORY = 0x16;

    var BUTTON_UP = 8;
    var BUTTON_DOWN = 4;
    var BUTTON_RIGHT = 2;
    var BUTTON_LEFT = 1;
    var BUTTON_1 = 64;
    var BUTTON_2 = 32;
    var BUTTON_A = 256;
    var BUTTON_B = 128;
    var BUTTON_PLUS = 16;
    var BUTTON_MINUS = 512;
    
    var BUTTON_C = 0x04;
    var BUTTON_Z = 0x02;

    var HEXCODES = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];
    
    var KEY_MAPPINGS = new Array();
    var defaultEnabled = new Array();

    var keyCodes = 0;
    var primary = 0;
    var flags = 0;
    
    var remotes = new Array();
    var commands = new Array(0x21);
    
    var starttime;
    var sampleRate;
    var timer;
    
    var internalWidth;
    var internalHeight;
    var externalWidth;
    var externalHeight;
    var offsetx;
    var offsety;
    var xratio;
    var yratio;
    
    function WiiRemote()
    {
        this.bitmap = 0;
        this.attach = 0;
        this.twist = 0;
        this.distance = 0;
        this.cursorx = 0;
        this.cursory = 0;
        
        this.activated = new Array();
        
        this.parseBitmap = function(hold)
        {
            var oldbitmap = this.bitmap; 
            
            this.bitmap = ((hold & 0x1F80) >> 3) | (hold & 0x1F);

            return (oldbitmap != this.bitmap);
        };
        
        this.parseAttachments = function(hold)
        {
            var oldattach = this.attach;
            
            this.attach = ((hold >>> 13) & 0x0F);
            
            return (oldattach != this.attach);
        };
        
        this.parseTwist = function(rollx, rolly)
        {
            var temp;
            var oldtwist = this.twist;
            
            if(!this.activated[COMMAND_TWIST]) return false;
            
            temp = Math.floor((Math.atan2(rolly, rollx) * 180 / Math.PI));
            if(temp < 0) this.twist = (360+temp);
            else this.twist = temp;
            
            return (oldtwist != this.twist);
        };
        
        this.parseDistance = function(distance)
        {
            var olddist = this.distance;
            
            if(!this.activated[COMMAND_DISTANCE]) return false;
            
            this.distance = Math.floor(distance * 100);
            
            return (olddist != this.distance);
        };
        
        this.parseCursor = function(cursorx, cursory)
        {
            if(!this.activated[COMMAND_CURSORX]) return false;
            
            if(!cursorx || !cursory)
            {
                cursorx = 0;
                cursory = 0;
            }
            
            if(xratio) this.cursorx = Math.max(0, Math.floor((cursorx-offsetx) * xratio));
            else this.cursorx = cursorx;
            
            if(yratio) this.cursory = Math.max(0, Math.floor((cursory-offsety) * yratio));
            else this.cursory = cursory;
            
            return true;
        };
    }

    function initMappings()
    {
        for(var i=0; i<4; i++) remotes[i] = new WiiRemote();
        
        /* Key Mappings */
        KEY_MAPPINGS[178] = BUTTON_LEFT;
        KEY_MAPPINGS[175] = BUTTON_UP;
        KEY_MAPPINGS[177] = BUTTON_RIGHT;
        KEY_MAPPINGS[176] = BUTTON_DOWN;

        KEY_MAPPINGS[13] = BUTTON_A;

        KEY_MAPPINGS[171] = BUTTON_B;
        KEY_MAPPINGS[172] = BUTTON_1;
        KEY_MAPPINGS[173] = BUTTON_2;
        KEY_MAPPINGS[174] = BUTTON_PLUS;
        KEY_MAPPINGS[170] = BUTTON_MINUS;

        /* Disallow the default actions */
        defaultEnabled[BUTTON_LEFT]  = false;
        defaultEnabled[BUTTON_UP]    = false;
        defaultEnabled[BUTTON_RIGHT] = false;
        defaultEnabled[BUTTON_DOWN]  = false;
        defaultEnabled[BUTTON_A]     = false;
        defaultEnabled[BUTTON_B]     = false;
        defaultEnabled[BUTTON_1]     = false;
        defaultEnabled[BUTTON_2]     = false;
        defaultEnabled[BUTTON_PLUS]  = false;
        defaultEnabled[BUTTON_MINUS] = false;
    }

    function getWiiRemoteSWF(id)
    {
        var div = document.createElement("div");
        
        div.style.width = "1px";
        div.style.height = "1px";
        div.style.zIndex = "-1";
        div.style.position = "absolute";
        div.style.top = "0px";
        div.style.left = "0px";
        div.style.background = "#FFFFFF";
        
        div.innerHTML = '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0" width="100%" height="100%" id="WiiRemoteSenderFlash" align="middle">' +
                        '<param name="allowScriptAccess" value="sameDomain" />' +
                        '<param name="movie" value="WiiRemoteSender.swf?commandid='+id+'" />' +
                        '<param name="quality" value="high" />' +
                        '<param name="bgcolor" value="#FFFFFF" />' +
                        '</object>';
                        
        return div;
    }
    
    function getCommand(index)
    {   
        if(!commands[index]) 
        {
            commands[index] = getWiiRemoteSWF(index);
            document.body.appendChild(commands[index]);
        }
        
        return commands[index];
    }
    
    /*======== Callback APIs =========*/

    function initializeWiiCadeAPI(fps, width, height)
    {
        var tags = document.getElementsByTagName("object");
        var object;

        //FIX ME: What about sites that size their movies with percents?
        
        for(var i=0; i<tags.length && !object; i++)
        {
            if(tags[i].width > 500 || tags[i].height > 500) object = tags[i];            
        }
        
        internalWidth = width;
        internalHeight = height;
        externalWidth = object.width;
        externalHeight = object.height;
        offsetx = object.offsetLeft;
        offsety = object.offsetTop;
        xratio = internalWidth/externalWidth;
        yratio = internalHeight/externalHeight;
        sampleRate = fps;

        if(fps > 10) fps = 10;
        
        initMappings();
        
        document.addEventListener("keydown", handleKeyDown, false);
        document.addEventListener("keyup", handleKeyUp, false);
        document.addEventListener("keypress", handleKeyPress, false);
        document.addEventListener("mousedown", handleMouseDown, false);
        document.addEventListener("mouseup", handleMouseUp, false);

        starttime = new Date().getTime();
        timer = setInterval(updateRemotes, Math.floor(1000/fps));
    }
    
    function enableWiiButton(buttonCode, enable)
    {
         defaultEnabled[buttonCode] = enable;
    }
    
    function setSamplesPerSecond(sps)
    {
        sampleRate = sps;
        
        cancelInterval(timer);
        timer = setInterval(updateRemotes, Math.floor(1000/sps));
    }
    
    function setBackgroundColor(color)
    {
        //FIX ME: Overly simplistic implementation.
        var htmlcolor = "";
        
        for(var i=0; i<6; i++)
        {
            htmlcolor = HEXCODES[(color & 0x0F)] + htmlcolor;
            
            color >>>= 4;
        }
        
        document.firstChild.style.background = "#"+htmlcolor;
        document.body.style.background = "#"+htmlcolor;
    }
    
    function activateWiiRemoteFeature(remote, feature, activate)
    {
        remotes[remote].activated[feature - remote] = activate;

        if((feature - remote) == COMMAND_CURSORY) 
            remotes[remote].activated[COMMAND_CURSORX] = activate;
document.getElementById("debug").value = (remote+":"+feature+":"+(feature-remote))+", ";
    }
    
    /*======== Event Handlers ========*/

    function handleKeyDown(event)
    {
        var div = getCommand(COMMAND_BUTTONS+primary);

        if(KEY_MAPPINGS[event.keyCode])  remotes[primary].bitmap |= KEY_MAPPINGS[event.keyCode];

        div.style.width = (remotes[primary].bitmap+1)+"px";
    }

    function handleKeyUp(event)
    {
        var div = getCommand(COMMAND_BUTTONS+primary);

        if(KEY_MAPPINGS[event.keyCode])  remotes[primary].bitmap &= (KEY_MAPPINGS[event.keyCode] ^ 1023);

        div.style.width = (remotes[primary].bitmap+1)+"px";
    }

    function handleKeyPress(event)
    {
        var buttonCode = KEY_MAPPINGS[event.keyCode];
        
        if(!defaultEnabled[buttonCode])
        {
            event.preventDefault();
            event.stopPropagation();
        }
    }
    
    function handleMouseDown(event)
    {
        var div = getCommand(COMMAND_BUTTONS+primary);

        remotes[primary].bitmap |= BUTTON_A;

        div.style.width = (remotes[primary].bitmap+1)+"px";
    }
    
    function handleMouseUp(event)
    {
        var div = getCommand(COMMAND_BUTTONS+primary);

        remotes[primary].bitmap &= (BUTTON_A ^ 1023);

        div.style.width = (remotes[primary].bitmap+1)+"px";
    }
    
    function updateRemotes()
    {
        var remote;
        var temp;
        var oldflags = flags;
        var mask;
        
        for(var i=0; i<remotes.length; i++)
        {
            remote = opera.wiiremote.update(i);
            mask = (0x01 << (3+i));
            
            if(!remote.isEnabled) 
            {
                flags &= ~mask;
                continue;
            }
            
            flags |= mask;
            
            if(remote.isBrowsing)
            {
                primary = i;
                flags = (flags & 0xFFC) | (primary & 0x03);
            }
            else if(remote.hold != null)
            {
                if(remotes[i].parseBitmap(remote.hold)) 
                {
                    getCommand(i+COMMAND_BUTTONS).style.width = (remotes[i].bitmap+1)+"px";
                }
                
                if(remotes[i].parseAttachments(remote.hold))
                {
                    getCommand(i+COMMAND_ATTACH).style.width = (remotes[i].attach+1)+"px";
                }
            }
            
            
            if(remotes[i].parseTwist(remote.dpdRollX, remote.dpdRollY))
                getCommand(i+COMMAND_TWIST).style.width = (remotes[i].twist+1)+"px";
            
            if(remotes[i].parseDistance(remote.dpdDistance))
                getCommand(i+COMMAND_DISTANCE).style.width = (remotes[i].distance+1)+"px";
            
            
            if(remotes[i].parseCursor(remote.dpdScreenX, remote.dpdScreenY))
            {
                getCommand(i+COMMAND_CURSORX).style.width = (remotes[i].cursorx+1)+"px";
                getCommand(i+COMMAND_CURSORY).style.width = (remotes[i].cursory+1)+"px";
            }
        }
        
        if(flags != oldflags)
        {
            if(starttime > 0)
            {
                if(new Date().getTime() < starttime+2000) flags = 0;
                else starttime = 0;
            }
            
            getCommand(COMMAND_FLAGS).style.width = (flags+1)+"px";
        }
    }
    
/*    opera.wiiremote = {
        update: function(id)
        {
            if(id > 3)
            return {
                isEnabled: false
            };
            else    
            return {
                dpdScreenX: 10 + Math.floor(Math.random() * 20),
                dpdScreenY: 20 + Math.floor(Math.random() * 15),
                dpdRollX: 1.2,
                dpdRollY: 0.3,
                dpdDistance: 1.23  + Math.random() * 4,
                hold: Math.floor(Math.random() * 0xFFF),
                isEnabled: true,
                isBrowsing: (id == 0)
            };
        }
    };*/
