var config;
var POLL_DELAY = 5000;
var app = app || {};

app.updateNotification = $("#update-notification");

// Set the name of the hidden property and the change event for visibility
var hidden, visibilityChange;
if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support
  hidden = "hidden";
  visibilityChange = "visibilitychange";
} else if (typeof document.mozHidden !== "undefined") {
  hidden = "mozHidden";
  visibilityChange = "mozvisibilitychange";
} else if (typeof document.msHidden !== "undefined") {
  hidden = "msHidden";
  visibilityChange = "msvisibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
  hidden = "webkitHidden";
  visibilityChange = "webkitvisibilitychange";
}

/**
 * Displays or hides the network is open warning.
 */
function checkNetworkOpenWarning() {
	var timeText = (config.config.permitjoinfull >= 60) ? ((parseInt(config.config.permitjoinfull) / 60) + 1) + " minutes" : config.config.permitjoin + " seconds";
	if ($.trim($('#network-open-alert').html()).length) {
        // case 1 remove warning
        if (config.config.permitjoinfull === 0 && config.config.permitjoin === 0) {
			//$('#no-lights-info').removeClass('hidden');
            $('#network-open-alert').html("");
			$('#btn-open-network').text("Open Network");
            return;
        }

        // case 2 warning already visible, update
		if (config.config.permitjoinfull > 0 || config.config.permitjoin > 0) {
			var txt = '<div class="alert alert-info">';
			txt += '<strong>Info!</strong> Network open. Check the <a href="index.html">main page</a> if new Lights where found. '+ timeText +' left';
			txt += '</div>';
			$('#network-open-alert').html(txt);
			return;
		}
    }

    // case 3 display warning
    if (config.config.permitjoinfull > 0 || config.config.permitjoin > 0) {
	    $('#no-lights-info').addClass('hidden');
        var txt = '<div class="alert alert-info">';
        txt += '<strong>Info!</strong> Network open. Check the <a href="index.html">main page</a> if new Lights where found. '+ timeText +' left';
        txt += '</div>';
        $('#network-open-alert').html(txt);
		$('#btn-open-network').text('Close Network');
    }
}

/**
 * Displays or hides the otau is busy warning.
 */
function checkOtauBusyWarning() {
	var flsUpdated = false;

	if ((localStorage.flsUpdated != null) && (localStorage.flsUpdated != undefined)) {
		flsUpdated = localStorage.flsUpdated;
    }

	//if update in progress
    if (config.config.otaustate === "busy") {
        $("#otau-alert").removeClass('hidden');
		if (!$("#otau-alert-done").hasClass('hidden')) {
			$("#otau-alert-done").addClass('hidden');
		}
		flsUpdated = true;
		localStorage.setItem("flsUpdated",flsUpdated);
    } else {
	//if not updating (otaustate == "idle")
		if (flsUpdated == true || flsUpdated == "true") {
			//if lights were updated recently, show update done message
		    if (!$("#otau-alert").hasClass('hidden')) {
                $("#otau-alert").addClass('hidden');
            }

            $("#otau-alert-done").removeClass('hidden');
			sessionStorage.setItem("config",JSON.stringify(config));
		} else {
			//if lights were not updated recently just hide update message
			if (!$("#otau-alert").hasClass('hidden')) {
				$("#otau-alert").addClass('hidden');
			}
		}
    }
}


/**
 * Displays or hides the update is available notification.
 */
function checkUpdateNotification() {
    var curVersion = config.config.swversion;
    var updateVersion = config.config.swupdate.version;

    if (compareVersionNumbers(curVersion, updateVersion) === -1)
    {
        app.updateNotification.removeClass('hidden');
    }
    else if (config.config.fwneedupdate)
    {
        app.updateNotification.removeClass('hidden');
    }
    else {
        if (! app.updateNotification.hasClass('hidden')) {
            app.updateNotification.addClass('hidden');
        }
    }
}

/**
 * Updates configuration state.
 */
function checkUpdatedData() {

    if (hidden !== 'undefined') {
        if (document[hidden] === true) {
            console.log('don\'t update while browser window is hidden');
            setTimeout(checkUpdatedData, POLL_DELAY);
            return;
        }
    }

    $.ajax({
        url: 'api/' + apikey,
        dataType: 'json',
        type: 'GET',
        cache: false,
        contentType: 'application/json; charset=utf-8',
        headers: {
            'If-None-Match': config.etag,
            'Accept': apiversion
        },
        success: function(json, status, xhr) {
			//alert("xhr.status:" + xhr.status);
			//stop gw scanning
			scanGatewayState = STOP_GW_SCAN;

            if (xhr.status === 304) {
                // call self
                setTimeout(checkUpdatedData, POLL_DELAY);
                return;
            }

            // if the group count changes rebuild ui completely
            // note: since groups is a object noth a array we can't use groups.length here
            if (_.size(config.groups) !== _.size(json.groups)) {
                config = json;
                config.etag = xhr.getResponseHeader("ETag");

                // all new
                groupArr = [];
                $(pageLightList).html("");

                showConfiguration();

                // make available for caching
                if (Modernizr.sessionstorage) {
                    sessionStorage.config = xhr.responseText;
                }
                // call self
                setTimeout(checkUpdatedData, POLL_DELAY);
                return;
            }

			var g;
            var l;
            var txt;
            var changed = false;

			// detect new lights automatically
            if (_.size(config.lights) < _.size(json.lights)) {
			    changed = true;
			}
			if (_.size(config.lights) > _.size(json.lights)) {
				//remove lights from undef location
				for (id in config.lights) {
					if (!(_.contains(json.lights, config.lights[id]))) {
						$('tr.undef[data-ulid=' + config.lights[id].id + ']').remove();
					}
				}

				changed = true;
			}

            for (g in json.groups) {
                json.groups[g].id = g;
            }

            for (l in json.lights) {
                json.lights[l].id = l;
            }

			if (_.size(json.sensors) !== _.size(config.sensors)) {
				changed = true;
			} else {
				for (s in json.sensors) {
					var sensor = json.sensors[s];
					var sensorCache = config.sensors[s];
					if (sensorCache !== undefined) {
						if ((sensor.etag != sensorCache.etag)) {
							changed = true;
						}
					}
				}
			}

			var rebuildGroups = false;

			if (_.size(json.rules) !== _.size(config.rules)) {
				rebuildGroups = true;
			} else {
				for (r in json.rules) {
					var rule = json.rules[r];
					var rulesCache = config.rules[r];

					if (rulesCache !== undefined) {
						if ((rule.etag != rulesCache.etag)) {
							rebuildGroups = true;
							break;
						}
					}
				}
			}

            for (g in json.groups) {
                var group = json.groups[g];
                var groupCache = config.groups[g];

                // needed to be equal api that lights use
                group.apitype = group.type;
                group.type = TYPE_GROUP;
                group.hasColor = true;
                group.state = group.action;

                if (groupCache !== undefined) {
                    if ((group.etag != groupCache.etag) || (group.lights.length !== groupCache.lights.length) || rebuildGroups === true) {
						config = json;
                        txt = groupToHtml(group, json.lights);
                        $('div.location[data-gid="' + group.id + '"]').replaceWith(txt);
                        changed = true;
                    }
                }
            }

            for (l in json.lights) {
                var light = json.lights[l];
                var lightCache = config.lights[l];

                if (lightCache !== undefined) {
                    if (light.etag != lightCache.etag) {
						txt = lightToHtml(light,true);
						$('tr[data-lid="' + light.id + '"]').each(function() {
							if (!$(this).hasClass('hidden')) {
								$(this).replaceWith(txt);
							}
						});

						$('tr[data-ulid="' + light.id + '"] td.undef-name').text(light.name);
						if (light.modelid != "") {
							$('tr[data-ulid="' + light.id + '"] td.modelid').text(light.modelid);
						}
						if (light.state.reachable == false) {
							$('tr[data-ulid="' + light.id + '"]').addClass("not_reachable");
						} else {
							$('tr[data-ulid="' + light.id + '"]').removeClass("not_reachable");
						}
                        changed = true;
                    }
                }
            }

            // check for changed fields
            for (var k in config.config) {
                if (k in json.config) {
                    if (typeof(config.config[k]) === 'object')
                        continue;

                    if (config.config[k] !== json.config[k]) {
                        changed = true;
                    }
                } else {
                    changed = true;
                }
            }

            config.config.permitjoin = json.config.permitjoin;
			config.config.permitjoinfull = json.config.permitjoinfull;
            // always copy version information
            config.config.fwneedupdate = json.config.fwneedupdate;
            config.config.fwversion = json.config.fwversion;
            config.config.swversion = json.config.swversion;
            config.config.swupdate = json.config.swupdate;

            // always copy ota information
            config.config.otauactive = json.config.otauactive;
            config.config.otaustate = json.config.otaustate;

            if (changed) {
                config = json;
				showConfiguration();

                // make available for caching
                if (Modernizr.sessionstorage) {
                    sessionStorage.config = xhr.responseText;
                }

                // update lights
                updateLights();
                recalcAllGroupParams();
                adjustLightNames();
            }

            checkNetworkOpenWarning();
            checkOtauBusyWarning();
            checkUpdateNotification();

            config.etag = xhr.getResponseHeader("ETag");
            if (!config.etag) {
                config.etag = "";
            }

            // call self
            setTimeout(checkUpdatedData, POLL_DELAY);
        },
        error: function(jqXHR, textStatus, errorThrown) {
            if (jqXHR.status == 0 || textStatus == "timeout") {
				if (config.config.updatechannel === "alpha") {
					showAlert('alert-warning', '<b>Lost connection!</b> Trying to reconnect.');
					// try from beginning on (also to clear the alert box on success)

					if (scanGatewayState == STOP_GW_SCAN) {
						scanGatewayState = START_GW_SCAN;
						origin = LIGHT_CONTROL;
						getIPs(function(ip){
							//local IPs
							if (ip.match(/^(192\.168\.|169\.254\.|10\.|172\.(1[6-9]|2\d|3[01]))/)) {
								networks.push(ip.substring(0, ip.lastIndexOf(".") + 1));
								scanNetworks();
							}
						});
					}
				}
                setTimeout(getFullConfiguration, 1000);
                return;
            }

            switch (jqXHR.status) {
            case 403:
                window.location.assign("/pwa/login.html");
                break;

            default:
				if (config.config.updatechannel === "alpha") {
					showAlert('alert-warning', '<b>Lost connection!</b> Trying to reconnect.');
					// try from beginning on (also to clear the alert box on success)

					if (scanGatewayState == STOP_GW_SCAN) {
						scanGatewayState = START_GW_SCAN;
						origin = LIGHT_CONTROL;
						getIPs(function(ip){
							//local IPs
							if (ip.match(/^(192\.168\.|169\.254\.|10\.|172\.(1[6-9]|2\d|3[01]))/)) {
								networks.push(ip.substring(0, ip.lastIndexOf(".") + 1));
								scanNetworks();
							}
						});
					}
					setTimeout(checkUpdatedData, POLL_DELAY);
					break;
				}
            }
        },
        timeout: 10000
    });
}

function showConfiguration() {
	clearAlert();
    // update lights
    updateLights();

	var lightCount = 0;
	var groupCount = (_.size(config.groups));

	for (lid in config.lights) {
		//dont display white channel of multi-devices
		var mac = config.lights[lid].uniqueid.substring(0,config.lights[lid].uniqueid.indexOf("-"));
		var multideviceWhiteChannel = false;
		var hascolor = (config.lights[lid].state.colormode === undefined) ? false : true;

		//if (config.config.rgbwdisplay === "1") {
			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 && config.lights[lid].id != config.lights[i].id && hascolor == false && masterHasColor == true) {
					multideviceWhiteChannel = true;

					// remove white channel from view
					$('.light_item[data-lid="'+ config.lights[lid].id +'"]').html("");

					// mark the other light as multidevice master
					config.lights[i].multideviceID = config.lights[lid].id;
					config.lights[i].multideviceUID = config.lights[lid].uniqueid;

					// multidevice is only off when both lights are off
					if (!config.lights[i].state.on && !config.lights[lid].state.on) {
						$('.onoff_button[data-lid="'+ config.lights[i].id +'"]').removeClass('light_on');
						$('.onoff_button[data-lid="'+ config.lights[i].id +'"]').removeClass('light_colorloop');
					} else if (config.lights[i].state.on || config.lights[lid].state.on) {
						if (config.lights[i].state.effect == "colorloop") {
							$('.onoff_button[data-lid="'+ config.lights[i].id +'"]').addClass('light_colorloop');
						} else {
							$('.onoff_button[data-lid="'+ config.lights[i].id +'"]').addClass('light_on');
						}
					}

					//display the higher level percent value of rgb or white channel
					if (config.lights[i].state.bri >= config.lights[lid].state.bri || localStorage.getItem("whitebar-"+config.lights[i].id) === "hidden") {
						$('.light_item[data-lid="'+ config.lights[i].id +'"] td:nth-child(2)').html(config.lights[i].levelPercent + '%');
					} else {
						$('.light_item[data-lid="'+ config.lights[i].id +'"] td:nth-child(2)').html(config.lights[lid].levelPercent + '%');
					}
					break;
				}
			}
		//}

		if (multideviceWhiteChannel == false) {
			lightCount++;
			checkLightInGroup(config.lights[lid]);
		}
	}

	if (lightCount === 0 && groupCount === 0) {
		$('#no-lights-info').removeClass('hidden');
	} else {
		$('#no-lights-info').addClass('hidden');
	}

	// update groups
    checkGroups(config.groups);
    recalcAllGroupParams();

	$('tr.undef td:nth-child(3) a div').removeClass("disabled");
	$('tr.undef td:nth-child(3) a').attr("href","#addToGroupModal");

	//check if undefContent is empty, then hide whole container
	if ($.trim($("#undefContent").html()) == '') {
		$('#undefLightList').addClass('hidden');
	} else {
		$('#undefLightList').removeClass('hidden');
	}

	adjustUndefLightNames();
    checkOtauBusyWarning();
    checkUpdateNotification();
}

/**
 * Get full configuration state from cache if available.
 * @return {bool} true if loaded from cache
 */
function getFullConfigurationCache() {
    if (Modernizr.sessionstorage) {
        if (sessionStorage.config) {
            config = JSON.parse(sessionStorage.config);
            showConfiguration();

			for (g in config.groups) {
				$('#selectGroup').append('<option value="'+ config.groups[g].id +'">'+ config.groups[g].name +'</option>');
			}
			if ($('#selectGroup > option').length == 0) {
				$('#addToGroupInfo').html('<span class="label label-info">Info</span> No groups found. Create a new group first.');
			} else {
				$('#addToGroupInfo').html('');
			}
			if (_.size(config.groups) == 0 && _.size(config.lights) > 0) {
				$('#new-lights-found-info').html('<div style="margin:10px;"><table><tr><td><span style="margin-right:5px;" class="label label-info">Info</span></td><td>New lights were found!</td></tr><tr><td></td><td style="white-space:normal;">In order to control them click at the + button to add them to a group. Or use the Groups menu.</td></tr></table></div>');
			}

            setTimeout(checkUpdatedData, 500);
            return true;
        }
    }
    return false;
}

/**
 * Initial get full configuration state.
 */
function getFullConfiguration() {

    $.ajax({
        url: 'api/' + apikey,
        dataType: 'json',
        type: 'GET',
        cache: false,
        contentType: 'application/json; charset=utf-8',
        headers: { 'Accept': apiversion },
        success: function(json, status, xhr) {
			//stop gw scanning
			scanGatewayState = STOP_GW_SCAN;

			config = json;
            config.etag = xhr.getResponseHeader("ETag");

            showConfiguration();

			for (g in config.groups) {
				$('#selectGroup').append('<option value="'+ config.groups[g].id +'">'+ config.groups[g].name +'</option>');
			}
			if ($('#selectGroup > option').length == 0) {
				$('#addToGroupInfo').html('<span class="label label-info">Info</span> No groups found. Create a new group first.');
			} else {
				$('#addToGroupInfo').html('');
			}
			if (_.size(config.groups) == 0 && _.size(config.lights) > 0) {
				$('#new-lights-found-info').html('<div style="margin:10px;"><table><tr><td><span style="margin-right:5px;" class="label label-info">Info</span></td><td>New lights were found!</td></tr><tr><td></td><td style="white-space:normal;">In order to control them click at the + button to add them to a group. Or use the Groups menu.</td></tr></table></div>');
			}

            // make available for caching
            if (Modernizr.sessionstorage) {
                sessionStorage.config = xhr.responseText;
            }

            setTimeout(checkUpdatedData, 5000);
        },
        error: function(jqXHR, textStatus, errorThrown) {
            switch (jqXHR.status) {
            case 403:
                window.location.assign("/pwa/login.html");
                break;

            default:
				if (config.config.updatechannel === "alpha") {
					showAlert('alert-warning', '<b>Lost connection!</b> Trying to reconnect.');

					if (scanGatewayState == STOP_GW_SCAN) {
						scanGatewayState = START_GW_SCAN;
						origin = LIGHT_CONTROL;
						getIPs(function(ip){
							//local IPs
							if (ip.match(/^(192\.168\.|169\.254\.|10\.|172\.(1[6-9]|2\d|3[01]))/)) {
								networks.push(ip.substring(0, ip.lastIndexOf(".") + 1));
								scanNetworks();
							}
						});
					}
				}
				setTimeout(getFullConfiguration, 1000);
                break;
            }
        },
        timeout: 10000
    });
}
