/**********************************************************************************************
*
* JMRI JSON WebSockets and Ajax communication javascript
* File version 1.0 (old): script 'ThrottleMonitor.py' must be loaded for throttle support
* File version 2.0: native JSON throttle support - doesn't need script 'ThrottleMonitor.py' anymore
*
* >>> This file version: 2.1 - from original 'jquery.jmri.js' modified by Oscar Moutinho (oscar.moutinho@gmail.com)
*
* Using HTML5 and jQuery 2...
* Note that this JMRI extension relies on the jquery-websocket v.0.0.4 extension.
*
**********************************************************************************************/

//----------------------------------------- Manage JMRI WebSockets
(function($) {
    $.extend({
        JMRI: function(url, bindings) {
            var jmri = {};
            if (typeof(url) === 'string') {
                jmri.url = url;
            } else {
                jmri.url = document.URL.split('/')[0] + '//' + document.URL.split('/')[2] + '/json/';
                bindings = url;
            }
            // Default event handlers that do nothing
            jmri.toSend = function(data) {};
            jmri.fullData = function(data) {};
            jmri.error = function(code, message) {};
            jmri.end = function() {};
            jmri.ready = function(jsonVersion, jmriVersion, railroadName) {};
            jmri.throttle = function(name, address, speed, forward, fs) {};
            jmri.light = function(name, userName, comment, state) {};
            jmri.reporter = function(name, userName, state, comment, report, lastReport) {};
            jmri.sensor = function(name, userName, comment, inverted, state) {};
            jmri.turnout = function(name, userName, comment, inverted, state) {};
            jmri.signalHead = function(name, userName, comment, lit, appearance, held, state, appearanceName) {};
            jmri.signalMast = function(name, userName, aspect, lit, held, state) {};
            jmri.route = function(name, userName, comment, state) {};
            jmri.memory = function(name, userName, comment, value) {};
            jmri.power = function(state) {};
            // Add user-defined handlers to the settings object
            $.extend(jmri, bindings);
            // Constants
            jmri.powerUNKNOWN = 0;
            jmri.powerON = 2;
            jmri.powerOFF = 4;
            jmri.turnoutUNDEFINED = 0;
            jmri.turnoutUNKNOWN = 1;
            jmri.turnoutCLOSED = 2;
            jmri.turnoutTHROWN = 4;
            jmri.routeDISABLED = 0;
            jmri.routeUNDEFINED = 1;
            jmri.routeACTIVE = 2;
            jmri.routeINACTIVE = 4;
            jmri.TRUE = true;
            jmri.FALSE = false;
            jmri.YES = 1;
            jmri.NO = 0;
            jmri.EMERGENCY_STOP = '-1.0';
            jmri.STOP = '0.0';
            jmri.FULL_SPEED = '1.0';
            // Getters and Setters
            var roster = null;
            jmri.getRosterGroups = function() {
                if (!roster) roster = loadRoster();
                var rosterGroupsList = [];
                if (roster) {
                    roster.find('roster-config roster locomotive').each(function() {
                        $(this).find('attributepairs keyvaluepair').each(function() {
                            var key = $(this).find('key').text();
                            if (key.split(':')[0] == 'RosterGroup') {
                                var rosterGroup = key.split(':')[1];
                                var value = $(this).find('value').text();
                                if (value == 'yes' && rosterGroupsList.indexOf(rosterGroup) == -1) rosterGroupsList.push(rosterGroup);
                            }
                        });
                    });
                }
                return rosterGroupsList.sort();
            };
            jmri.getRoster = function(group) {
                if (!roster) roster = loadRoster();
                var locoList = [];
                if (roster) {
                    roster.find('roster-config roster locomotive').each(function() {
                        var inGroup = false;
                        if (group) {
                            $(this).find('attributepairs keyvaluepair').each(function() {
                                var key = $(this).find('key').text();
                                if (key.split(':')[0] == 'RosterGroup') {
                                    key = key.split(':')[1];
                                    var value = $(this).find('value').text();
                                    if (key == group && value == 'yes') inGroup = true;
                                }
                            });
                        } else inGroup = true;
                        if (inGroup) {
                            var loco = {
                                name: $(this).attr('id'),
                                roadNumber: $(this).attr('roadNumber'),
                                roadName: $(this).attr('roadName'),
                                mfg: $(this).attr('mfg'),
                                owner: $(this).attr('owner'),
                                model: $(this).attr('model'),
                                dccAddress: parseInt($(this).attr('dccAddress'), 10),
                                imageFilePath: $.trim($(this).attr('imageFilePath')),
                                iconFilePath: $.trim($(this).attr('iconFilePath'))
                            };
                            locoList.push(loco);
                        }
                    });
                }
                return locoList;
            };
            jmri.getRosterItem = function(name) {
                if (!roster) roster = loadRoster();
                var loco = null;
                if (roster) {
                    roster.find('roster-config roster locomotive').each(function() {
                        if ($(this).attr('id') == name) {
                            loco = {
                                name: $(this).attr('id'),
                                fileName: $(this).attr('fileName'),
                                roadNumber: $(this).attr('roadNumber'),
                                roadName: $(this).attr('roadName'),
                                mfg: $(this).attr('mfg'),
                                owner: $(this).attr('owner'),
                                model: $(this).attr('model'),
                                dccAddress: parseInt($(this).attr('dccAddress'), 10),
                                comment: $(this).attr('comment'),
                                maxSpeed: parseInt($(this).attr('maxSpeed'), 10),
                                imageFilePath: $.trim($(this).attr('imageFilePath')),
                                iconFilePath: $.trim($(this).attr('iconFilePath')),
                                URL: $.trim($(this).attr('URL')),
                                IsShuntingOn: $.trim($(this).attr('IsShuntingOn')).toUpperCase(),
                                f: new Array(29)
                            };
                            for (var i = 0; i < 29; i++) loco.f[i] = null;
                            $(this).find('functionlabels functionlabel').each(function() {
                                var n = parseInt($(this).attr('num'), 10);
                                var f = {
                                    lockable: ($(this).attr('lockable') == 'true'),
                                    functionlabel: $(this).text(),
                                    functionImage: $.trim($(this).attr('functionImage')),
                                    functionImageSelected: $.trim($(this).attr('functionImageSelected'))
                                };
                                loco.f[n] = f;
                            });
                        }
                    });
                }
                return loco;
            };
            var loadRoster = function() {   //Retrieve roster
                var roster = null;
                $.ajax({
                    url: '/roster?format=xml',
                    async: false,
                    cache: false,
                    type: 'GET',
                    dataType: 'xml',
                    error: function(jqXHR, textStatus, errorThrown) {
                        if(jqXHR.status == 404) jmri.error(jqXHR.status, 'Roster empty.\nNo locos defined in JMRI.');
                        else jmri.error(jqXHR.status, 'Response:\n' + jqXHR.responseText + '\n\nError:\n' + errorThrown);
                    },
                    success: function(xmlReturned, status, jqXHR) {
                                            roster = $(xmlReturned);
                                            if (xmlReturned === null) {
                                                jmri.error(200, 'Roster empty.\nNo locos defined in JMRI.');
                                            }
                                        }
                });
                return roster;
            };
            jmri.getObjectList = function(listType) {   //Retrieve a JSON list of objects
                var list = [];
                $.ajax({
                    url: jmri.url + listType,
                    async: false,
                    cache: false,
                    type: 'GET',
                    dataType: 'json',
                    error: function(jqXHR, textStatus, errorThrown) {
                        jmri.error(jqXHR.status, 'Response:\n' + jqXHR.responseText + '\n\nError:\n' + errorThrown);
                    },
                    success: function(listReturned, status, jqXHR) {list = listReturned;}
                });
                return list;
            };
            var heartbeatDelay; // Heartbeat timer delay
            var heartbeat = null;   // Heartbeat timer
            jmri.closeSocket = function() {jmri.socket.close();};
            jmri.getJMRI = function(type, name) {
                if (!heartbeat) {jmri.error(0, 'The JMRI WebSocket service is not ready.\nSolve the problem and refresh web page.'); return;}
                var lp = (name) ? {"name":name} : {};
                jmri.toSend(JSON.stringify({"type":type,"data":lp}));
                jmri.socket.send(type, lp);
            };
            jmri.setJMRI = function(type, name, args, method) {
                if (!heartbeat) {jmri.error(0, 'The JMRI WebSocket service is not ready.\nSolve the problem and refresh web page.'); return;}
                var lp = (name) ? {"name":name} : {};
                jmri.toSend(JSON.stringify({"type":type, "data":jmri.jsonConcat(lp, args)}));
                jmri.socket.send(type, jmri.jsonConcat(lp, args), method);
            };
            jmri.jsonConcat = function(o1, o2) {    // Concatenate JSON name-value pair lists
                var o = {};
                var key;
                for (key in o1) o[key] = o1[key];
                for (key in o2) o[key] = o2[key];
                return o;
            };
            // WebSocket
            jmri.socket = $.websocket(jmri.url.replace(/^http/, 'ws'), {
                close: function() { // Stop the heartbeat when the socket closes
                    if (heartbeat) {
                        clearInterval(heartbeat);
                        heartbeat = null;
                    }
                },
                message: function(e) {jmri.fullData(e.originalEvent.data);},
                events: {
                    error: function(e) {jmri.error(e.data.code, e.data.message);},
                    pong: function(e) {},
                    goodbye: function(e) {
                        jmri.socket.close();
                        jmri.end();
                    },
                    hello: function(e) {    // Handle the initial handshake response from the server
                        heartbeatDelay = e.data.heartbeat;
                        heartbeat = setInterval(function() {jmri.toSend(JSON.stringify({"type":"ping"})); jmri.socket.send('ping');}, heartbeatDelay);
                        jmri.ready(e.data.json, e.data.JMRI, e.data.railroad);
                    },
                    throttle: function(e) {
                        var functions = new Array(29);
                        for (var i = 0; i < 29; i++) functions[i] = e.data['F' + i];
                        jmri.throttle(e.data.throttle, e.data.address, e.data.speed, e.data.forward, functions);
                    },
                    light: function(e) {jmri.light(e.data.name, e.data.userName, e.data.comment, e.data.state);},
                    reporter: function(e) {jmri.reporter(e.data.name, e.data.userName, e.data.state, e.data.comment, e.data.report, e.data.lastReport);},
                    sensor: function(e) {jmri.sensor(e.data.name, e.data.userName, e.data.comment, e.data.inverted, e.data.state);},
                    turnout: function(e) {jmri.turnout(e.data.name, e.data.userName, e.data.comment, e.data.inverted, e.data.state);},
                    signalHead: function(e) {jmri.signalHead(e.data.name, e.data.userName, e.data.comment, e.data.lit, e.data.appearance, e.data.held, e.data.state, e.data.appearanceName);},
                    signalMast: function(e) {jmri.signalMast(e.data.name, e.data.userName, e.data.aspect, e.data.lit, e.data.held, e.data.state);},
                    route: function(e) {jmri.route(e.data.name, e.data.userName, e.data.comment, e.data.state);},
                    memory: function(e) {jmri.memory(e.data.name, e.data.userName, e.data.comment, e.data.value);},
                    power: function(e) {jmri.power(e.data.state);}
                }
            });
            return jmri;
        }
    });
})(jQuery);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ End of file
