
var app = app || {};
var curInput;
var group;
var groupId = 0;
var sceneId = 0;
var TIMEOUT_AJAX = 10000;

var ERR_UNKNOWN = 1000;
var ERR_DUPLICATE_EXIST = 100;
var ERR_DEVICE_SCENES_TABLE_FULL = 402;

var deCONZ = deCONZ || {};
var config;
var multiDeviceIds = [];

/**
 * The scenes REST API handlers.
 */
(function(api) {
    api.config = api.config || {};
    api.config.groups = api.config.groups || {};

    api.scenes = {
        getGroup: function(id) {
            if (typeof id === 'number') {
                id = String(id);
            }

            if (typeof api.config.groups[id] !== 'undefined') {
                return api.config.groups[id];
            }

            return undefined;
        },

        getScene: function(gid, sid) {
            if (typeof gid === 'number') {
                gid = String(gid);
            }

            var group = this.getGroup(gid);

            if (group) {
                if (typeof sid === 'number') {
                    sid = String(sid);
                }

                for (var i = 0; i < group.scenes.length; i++) {
                    if (group.scenes[i].id === sid) {
                        return group.scenes[i];
                    }
                }
            }

            return undefined;
        },

        /**
         * Loads the scenes from gatway.
         *
         * @param {string} gid - The group identifier.
         */
        load: function(gid) {
            $.ajax({
                url: '/api/' + apikey + '/groups/' + gid,
                dataType: 'json',
                processData: false,
                cache: false,
                headers: { 'Accept': apiversion },
                success: function(json) {
                    if (typeof json !== 'object') {
                        console.log("unexpected response " + typeof json);
                        $(api).trigger('scenes.loadFailed', ERR_UNKNOWN);
                        return;
                    }
                    $(api).trigger('scenes.loaded', json);
                },
                error: function(jqXHR, textStatus, errorThrown) {
                    showAlert('alert-error', "<b>Error!</b> Loading scenes failed.","#scene-alerts");
                    $(api).trigger('scenes.loadFailed', ERR_UNKNOWN);
                },
                timeout: TIMEOUT_AJAX
            });
        },

        loaded: function(e, group) {
            // insert group id in each scene to make things easier
            for (var i = 0; i < group.scenes.length; i++) {
                group.scenes[i].gid = group.id;
            }
            api.config.groups[group.id] = group;
            $(this).trigger('scenes.changed', group);
        },

        /**
         * Adds a new scene to the group.
         *
         * @param {string} gid - The group identifier.
         * @param {string} name - The scene name.
         */
        add: function(gid, name) {
            var out = { "name" : name };
            $.ajax({
                url: '/api/' + apikey + '/groups/' + gid + '/scenes',
                type: 'POST',
                dataType: 'json',
                processData: false,
                cache: false,
                data: JSON.stringify(out),
                success: function(json) {
                    var succ = apiSuccess(json);

                    // got a new id append to scenes array and refresh ui
                    if (succ.id) {
                        $(api).trigger('scenes.added', [{gid: gid, id: succ.id, name: name},json] );
                    }
                    else {
                        $(api).trigger('scenes.addFailed', [ name, ERR_UNKNOWN ]);
                    }
                },
                error: function(jqXHR, textStatus, errorThrown) {

                    if (jqXHR.status === 400) { // bad Request
                        var err = apiError(jqXHR.responseText);

                        if (err.type === ERR_DUPLICATE_EXIST) {
                            $(api).trigger('scenes.addFailed', [ name, ERR_DUPLICATE_EXIST ]);
                        } else {
                            $(api).trigger('scenes.addFailed', [ name, ERR_UNKNOWN ]);
                        }
                    }
                },
                timeout: TIMEOUT_AJAX
            });
        },

        added: function(e, scene) {
            var group = this.scenes.getGroup(scene.gid);
            if (group) {
                // this.scenes.group.scenes.push(scene);
                group.scenes.push(scene);
                app.scenes.store(scene.gid, scene.id);
            }
            $(this).trigger('scenes.changed', group);
        },

        /**
         * Stores the current scene group state.
         *
         * @param {string} gid - The group identifier.
         * @param {string} sid - The scene identifier.
         */
        store: function(gid, sid) {
            var scene = this.getScene(gid, sid);

            if (!scene) {
                console.log('scene with id ' + sid + ' doesn\'t exist');
                return;
            }

            $.ajax({
                url: '/api/' + apikey + '/groups/' + gid + '/scenes/' + sid + '/store',
                type: 'PUT',
                cache: false,
                success: function(data) {
                    $(api).trigger('scenes.stored', [scene, data]);
                },
                error: function(jqXHR, textStatus, errorThrown) {
                    $(api).trigger('scenes.storeFailed', [ scene, ERR_UNKNOWN ]);
                },
                timeout: TIMEOUT_AJAX
            });
        },

        /**
         * Removes a scene from a group.
         *
         * @param {string} gid - The group identifier.
         * @param {string} sid - The scene identifier.
         */
        remove:  function(gid, sid) {
            var scene = this.getScene(gid, sid);

            if (!scene) {
                console.log('scene with id ' + sid + ' doesn\'t exist');
                return;
            }

            $.ajax({
                url: '/api/' + apikey + '/groups/' + gid + '/scenes/' + sid,
                type: 'DELETE',
                cache: false,
                success: function(json) {
                    var succ = apiSuccess(json);

                    // got a new id append to scenes array and refresh ui
                    if (succ.id) {
                        $(api).trigger('scenes.removed', scene);
                    }
                    else {
                        $(api).trigger('scenes.removeFailed', [ scene, ERR_UNKNOWN ]); 
                    }
                },
                error: function(jqXHR, textStatus, errorThrown) {
                    $(api).trigger('scenes.removeFailed', [ scene, ERR_UNKNOWN ]);
                },
                timeout: TIMEOUT_AJAX
            });
        },

        removed: function(e, scene) {
            var group = this.scenes.getGroup(scene.gid);

            if (group) {
                var found = false;

                for (var i = 0; i < group.scenes.length; i++) {
                    if (group.scenes[i].id === scene.id) {
                        group.scenes.splice(i, 1); // remove that scene
                        found = true;
                        break;
                    }
                }

                if (found) {
                    $(this).trigger('scenes.changed', group);
                }
            }
        },

        /**
         * Sets the name of a scene.
         *
         * @param {string} gid - The group identifier.
         * @param {string} sid - The scene identifier.
         * @param {string} name - The new scene name.
         */
        rename: function(gid, sid, name) {
            var scene = this.getScene(gid, sid);

            if (!scene) {
                console.log('scene with id ' + sid + ' doesn\'t exist');
                return;
            }

            // same name nothing todo
            if (scene.name === name) {
                return;
            }

            var oldname = scene.name;
            var out = { 'name': name };

            $.ajax({
                url: '/api/' + apikey + '/groups/' + gid + '/scenes/' + sid,
                type: 'PUT',
                dataType: 'json',
                processData: false,
                cache: false,
                data: JSON.stringify(out),
                success: function(data) {
                    scene.name  = name;
                    $(api).trigger('scenes.renamed', [ scene, name, oldname ]);
                },
                error: function(jqXHR, textStatus, errorThrown) {
                    $(api).trigger('scenes.renameFailed', [ scene, ERR_UNKNOWN ]);
                },
                timeout: TIMEOUT_AJAX
            });
        },

        renamed: function(e, scene, newname, oldname) {
            var group = this.scenes.getGroup(scene.gid);
            if (group) {
                $(this).trigger('scenes.changed', group);
            }
        },

        init: function() {
            $(api).on('scenes.loaded', this.loaded);
            $(api).on('scenes.added', this.added);
            $(api).on('scenes.removed', this.removed);
            $(api).on('scenes.renamed', this.renamed);
        }
    };
})(app);

/**
 * The scenes user interface handlers.
 */
app.ui = app.ui || {};

app.ui.scenes = {
    init: function() {
        $(app).on('scenes.changed', this.show);
        $(app).on('scenes.added', this.added);
        $(app).on('scenes.addFailed', this.addFailed);
        $(app).on('scenes.stored', this.stored);
        $(app).on('scenes.storeFailed', this.storeFailed);
        $(app).on('scenes.removed', this.removed);
        $(app).on('scenes.removeFailed', this.removeFailed);
        $(app).on('scenes.renamed', this.renamed);
        $(app).on('scenes.renameFailed', this.renameFailed);
    },

    stored: function(e, scene, json) {
		//clear warnings
		$('#warnings').html("");
        showAlert('alert-success', "<b>OK!</b> Scene <i>" + scene.name + "</i> stored.","#scene-alerts");
		for (var i in json) {
			if (json[i].error && json[i].error.type == ERR_DEVICE_SCENES_TABLE_FULL) {
				var addr = json[i].error.address; 
				var lid = addr.substring(addr.indexOf("lights/")+7, addr.length);
				if (!_.contains(multiDeviceIds,lid)) {
					appendWarning('alert-warning', "<b>Warning! </b>" + json[i].error.description);
				}		
			}
		}
    },

    storeFailed: function(e, scene, error) {
        showAlert('alert-error', "<b>Error!</b> Storing scene <i>" + scene.name + "</i> failed.","#scene-alerts");
    },

    added: function(e, scene, json) {
		//clear warnings
		$('#warnings').html("");
		
        showAlert('alert-success', "<b>OK!</b> Scene <i>" + scene.name + "</i> created.","#scene-alerts");
		for (var i in json) {
			if (json[i].error && json[i].error.type == ERR_DEVICE_SCENES_TABLE_FULL) {
				var addr = json[i].error.address; 
				var lid = addr.substring(addr.indexOf("lights/")+7, addr.length);
				if (!_.contains(multiDeviceIds,lid)) {
					appendWarning('alert-warning', "<b>Warning! </b>" + json[i].error.description);
				}		
			}
		}
    },

    addFailed: function(e, name, error) {
        if (error == ERR_DUPLICATE_EXIST) {
            showAlert('alert-error', "<b>Error!</b> The scene <i>" + name + "</i> already exist.","#scene-alerts");
        } else {
            showAlert('alert-error', "<b>Error!</b> Create scene <i>" + name + "</i> failed.","#scene-alerts");   
        }
    },

    removed: function(e, scene) {
        showAlert('alert-success', "<b>OK!</b> Scene <i>" + scene.name + "</i> deleted.","#scene-alerts");
    },

    removeFailed: function(e, name, error) {
        showAlert('alert-error', "<b>Error!</b> Deleting scene <i>" + scene.name + "</i> failed.","#scene-alerts");
    },

    renamed: function(e, scene, newname, oldname) {
        showAlert('alert-success', "<b>OK!</b> Scene <i>" + oldname + "</i> renamed to <i>" + newname + "</i>.","#scene-alerts");
    },

    renameFailed: function(e, scene, error) {
        showAlert('alert-error', "<b>Error!</b> Rename scene " + scene.name + " failed.","#scene-alerts");
    }
};

/**
 * Get the REST API error object.
 *
 * @param {string} responseText - The API error array returned in a response in JSON format.
 * @param {number} [index=0] - Index of the error to be returned.
 */
function apiError(responseText, index) {
    var err = { 
        'type': 0,
        'address': '/',
        'description': 'unknown error'
    };

    if (typeof index === 'undefined') {
        index = 0;
    }

    if (typeof responseText !== 'string') {
        return err;
    }

    var arr = JSON.parse(responseText);

    if (typeof arr === 'object' && arr.length >= 1) {
        var e = arr[index].error || {};
        if ((typeof e.type === 'undefined') ||
            (typeof e.address === 'undefined') || 
            (typeof e.description === 'undefined')) {
            return err;
        }

        return e;
    } 

    return err;
}

/**
 * Get the REST API success object for a given index.
 *
 * @param {object} arr - The API success array returned in a response.
 * @param {number} [index=0] - Index of the error to be returned.
 */
function apiSuccess(arr, index) {
    if (typeof index === 'undefined') {
        index = 0;
    }

    if ((typeof arr === 'object') && arr.length >= (index + 1)) {
		for (i in arr) {
			if (arr[i].success) {
				return arr[i].success;
			}
		}
    } 

    return {};
}

/**
 * Get the REST API Error object for a given index.
 *
 * @param {object} arr - The API success array returned in a response.
 * @param {number} [index=0] - Index of the error to be returned.
 */
function apiWarning(arr, index) {
    if (typeof index === 'undefined') {
        index = 0;
    }

    if ((typeof arr === 'object') && arr.length >= (index + 1)) {
		for (i in arr) {
			if (arr[i].Error) {
				return arr[i].Error;
			}
		}
    } 

    return {};
}

// Desktop and Android enter key
function onSceneEditKeyup(e) {
    if (e.keyCode === 13) { // enter
        if (e.target.nodeName === "INPUT") {
            if ($(e.target).data("sid") !== undefined) {
                e.target.blur();
            }
        }
    }
}

// Support iOS virtual keyboard "done" button
function onSceneEditBlur(e) {
    if (e.target.nodeName === "INPUT") {
        if ($(e.target).data("sid") !== undefined) {
            app.scenes.rename(groupId, $(e.target).data("sid"), e.target.value);
        }
    }
}

/**
 * Called then the delete button is clicked.
 * Sets the text in the modal according to the scene.
 *
 * @param {string} gid - The group identifier.
 * @param {string} sid - The scene identifier.
 */
app.ui.scenes.prepareDeleteScene = function(gid, sid) {
    var scene = app.scenes.getScene(gid, sid);
    if (scene) {
        sceneId = sid; // remember
        $('#deleteSceneQuestionLabel').html('Do you really want to delete the scene <b>' + scene.name + '</b>?');

        document.deleteSceneForm.onsubmit = function(e) {
            // e = e || window.event;
            $('#deleteModal').modal('hide');
            app.scenes.remove(gid, sid);
            e.preventDefault();
        };
    }
};

/**
 * Called then the store button is clicked.
 * Sets the text in the modal according to the scene.
 *
 * @param {string} gid - The group identifier.
 * @param {string} sid - The scene identifier.
 */
app.ui.scenes.prepareStoreScene = function(gid, sid) {
    var scene = app.scenes.getScene(gid, sid);
    if (scene) {
        sceneId = sid; // remember
        $('#storeSceneQuestionLabel').html('<p>Store current light state in the scene <b>' + scene.name + '</b>?</p>');

        document.storeSceneForm.onsubmit = function(e) {
            // e = e || window.event;
            $('#storeModal').modal('hide');
            app.scenes.store(gid, sid);
            e.preventDefault();
        };
    } else {
		var sceneName = $(':input[data-sid='+sid+']').val();
		$('#storeSceneQuestionLabel').html('<p>Store current light state in the scene <b>' + sceneName + '</b>?</p>');

        document.storeSceneForm.onsubmit = function(e) {
            // e = e || window.event;
            $('#storeModal').modal('hide');
            app.scenes.add(gid, sceneName);
            e.preventDefault();
        };
	}
};

/**
 * Builds and shows the scenes list ui.
 *
 * @param {object} e - The event object.
 */
app.ui.scenes.show = function(e) {

    var group = app.scenes.getGroup(groupId);
    var scenes = group.scenes;
    var txt = "";
	var iter = 0;
	
	var groupDeviceType = "";
	var modelId = "";
	if (config.sensors[group.devicemembership[0]] != undefined)
	{
		groupDeviceType = config.sensors[group.devicemembership[0]].type;
	}
	if (config.sensors[group.devicemembership[0]] != undefined &&
		config.sensors[group.devicemembership[0]].modelid != undefined &&
		config.sensors[group.devicemembership[0]].modelid != null) {
		modelId = config.sensors[group.devicemembership[0]].modelid;
	}
	
	if (modelId == "Scene Switch" || (modelId == "Lighting Switch" && config.sensors[group.devicemembership[0]].mode == 1)) { // use modelid
		var scene = {};
		txt += '<fieldset style="border:1px;border-style:groove;border-color:#ffffff;padding:10px;display:inline;margin-bottom:10px;">';
		txt += '<legend style="margin-bottom:0px;color:#ffffff;font-size:16px;border-bottom:0px;line-height:20px;width:110px;">Switch Scenes</legend>';
	
		scene = {"gid":group.id,"id":"1","name":"Scene 1"};
		for (s in group.scenes) {
			if (group.scenes[s].id == "1") {
				scene = group.scenes[s];
				break;
			}
		}
		txt += '<div class="row-fluid">';
		txt += '<div class="span12">';
		txt += '<p class="inner-addon right-addon"><img class="glyphicon_scene_edit" src="img/pencil.png"></img>';
		txt += '<input name="' + scene.name + '" value="' + scene.name + '" data-rgid="' + group.id + '" data-sid="' + scene.id + '" maxlength="32">';
		txt += '<a class="btn actionButton" href="#storeModal" data-toggle="modal" onclick="app.ui.scenes.prepareStoreScene('+ group.id + ',\'' + scene.id + '\');return false;">Store</a>';
		txt += '</p></div>';
		txt += '</div>';
		
		var sid = "2";
		if (modelId == "Lighting Switch") {
		    sid = "4";
		}
		scene = {"gid":group.id,"id":sid,"name":"Scene 2"};	
		for (s in group.scenes) {
			if (group.scenes[s].id == sid) {
				scene = group.scenes[s];
				break;
			}
		}
		txt += '<div class="row-fluid">';
		txt += '<div class="span12">';
		txt += '<p class="inner-addon right-addon"><img class="glyphicon_scene_edit" src="img/pencil.png"></img>';
		txt += '<input name="' + scene.name + '" value="' + scene.name + '" data-rgid="' + group.id + '" data-sid="' + scene.id + '" maxlength="32">';
		txt += '<a class="btn actionButton" href="#storeModal" data-toggle="modal" onclick="app.ui.scenes.prepareStoreScene('+ group.id + ',\'' + scene.id + '\');return false;">Store</a>';
		txt += '</p></div>';
		txt += '</div>';
        
		if (modelId == "Scene Switch") {
			scene = {"gid":group.id,"id":"3","name":"Scene 3"};
			for (s in group.scenes) {
				if (group.scenes[s].id == "3") {
					scene = group.scenes[s];
					break;
				}
			}
			txt += '<div class="row-fluid">';
			txt += '<div class="span12">';
			txt += '<p class="inner-addon right-addon"><img class="glyphicon_scene_edit" src="img/pencil.png"></img>';
			txt += '<input name="' + scene.name + '" value="' + scene.name + '" data-rgid="' + group.id + '" data-sid="' + scene.id + '" maxlength="32">';
			txt += '<a class="btn actionButton" href="#storeModal" data-toggle="modal" onclick="app.ui.scenes.prepareStoreScene('+ group.id + ',\'' + scene.id + '\');return false;">Store</a>';
			txt += '</p></div>';
			txt += '</div>';
			
		
			scene = {"gid":group.id,"id":"4","name":"Scene 4"};	
			for (s in group.scenes) {
				if (group.scenes[s].id == "4") {
					scene = group.scenes[s];
					break;
				}
			}
			txt += '<div class="row-fluid">';
			txt += '<div class="span12">';
			txt += '<p class="inner-addon right-addon"><img class="glyphicon_scene_edit" src="img/pencil.png"></img>';
			txt += '<input name="' + scene.name + '" value="' + scene.name + '" data-rgid="' + group.id + '" data-sid="' + scene.id + '" maxlength="32">';
			txt += '<a class="btn actionButton" href="#storeModal" data-toggle="modal" onclick="app.ui.scenes.prepareStoreScene('+ group.id + ',\'' + scene.id + '\');return false;">Store</a>';
			txt += '</p></div>';
			txt += '</div>';
		}
	}
	txt += '</fieldset>';
	
	for (s in group.scenes) {
		var scene = scenes[s];
		if ((scene.id < 5 && modelId == "Scene Switch") || ((scene.id == 1 || scene.id == 4) && modelId == "Lighting Switch" && config.sensors[group.devicemembership[0]].mode == 1)) {
		    continue;
		}
		txt += '<div class="row-fluid">';
		txt += '<div class="span12">';
		txt += '<p style="margin-left:10px;" class="inner-addon right-addon"><img class="glyphicon_scene_edit no_switch" src="img/pencil.png"></img>';
		txt += '<input name="' + scene.name + '" value="' + scene.name + '" data-rgid="' + group.id + '" data-sid="' + scene.id + '" maxlength="32">';
		//txt += '<div style="display:inline;">';
		txt += '<a class="btn actionButton" href="#storeModal" data-toggle="modal" onclick="app.ui.scenes.prepareStoreScene('+ group.id + ',\'' + scene.id + '\');return false;">Store</a>';
		txt += '<a class="btn btn-danger actionButton" href="#deleteModal" data-toggle="modal" onclick="app.ui.scenes.prepareDeleteScene('+ group.id + ',\'' + scene.id + '\');return false;">Delete</a>';
		//txt += '</div>';
		txt += '</p></div>';
		txt += '</div>';		
    }
              
    var div = document.querySelector('.sceneList');
    div.innerHTML = txt;

    document.addEventListener("blur", onSceneEditBlur, true);
    document.addEventListener("keyup", onSceneEditKeyup, true);
};

/**
 * Check if user did specify a name and if so sends the create scene command.
 */
app.ui.scenes.create = function() {
    var name = $('#sceneNameInput').val();

    $('#createModal').modal('hide');

    if (name.length > 0) {
        app.scenes.add(groupId, name);
    }
    else {
        showAlert('alert-warning', '<b>Note!</b> Skipped scene creation, no name was specified!',"#scene-alerts");
    }
};

/**
 * Helper Function to append Warnings
 */
function appendWarning(alert, text, container) {
    if (typeof(container) === 'undefined') {
        container = '#warnings';
    }

    var d = new Date();
    var timestr = d.toUTCString();
    var txt = "";

    txt += '<div style="" class="alert ' + alert + '">';
    txt += text;
    txt += ' <span class="pull-right hidden-phone">';
    txt += '</span></div>';

	setTimeout(function() {
		$(container).append(txt).scrollintoview();
	}, 250);
}

$(document).ready(function() {
    // init fastclick
    FastClick.attach(document.body);

    app.scenes.init();
    app.ui.scenes.init();

    initBranding();

	if (Modernizr.sessionstorage) {
		config = JSON.parse(sessionStorage.config);
		
		for (var id in config.lights) {
			var l = config.lights[id];
			var hascolor = (l.state.colormode === undefined) ? false : true;
			var mac = l.uniqueid.substring(0,l.uniqueid.indexOf("-"));
			
			for (i in config.lights) {
				var mac2 = config.lights[i].uniqueid.substring(0,config.lights[i].uniqueid.indexOf("-"));	
				var masterHasColor = (config.lights[i].state.colormode === undefined) ? false : true;
				if (mac == mac2 && id != i && hascolor == false && masterHasColor == true) {
					multiDeviceIds.push(id);				
					break;
				}		
			}
		}	
	}
	
    // prevent default sending of form
    $('form').submit(function(e){
        e.preventDefault();
        return false;
    });

     // clear name field
    $('#createModal').on('show', function () {
        $('#sceneNameInput').val("");
    });

     // focus input field 
    $('#createModal').on('shown', function () {
        setTimeout(function() {
            $('#sceneNameInput').focus();
        }, 100);
    });

    // focus input field 
    $('#deleteModal').on('shown', function () {
        var sub = $('input[type=submit]', this);
        setTimeout(function() { sub.focus(); }, 100);
    });

    // focus input field 
    $('#storeModal').on('shown', function () {
        var sub = $('input[type=submit]', this);
        setTimeout(function() { sub.focus(); }, 100);
    });

    groupId = getURLParameter("group");

    if (groupId !== null) {
       app.scenes.load(groupId);
    }
    else {
        showAlert('alert-error', '<b>Error!</b> No group specified!',"#scene-alerts");
    }
});
