var MAX_TRANSITION_TIME = 6;
var MOVE_NONE = 0;
var MOVE_LEVEL = 1;
var MOVE_COLOR = 2;
var MOVE_LEFT = 3;
var MOVE_LEVEL_WHITE = 4;

var EDIT_MODE_COLOR = 0;
var EDIT_MODE_COLOR_TEMPERATURE = 1;
var EDIT_MODE_MONOCHROMATIC = 2;

var colorEditMode = EDIT_MODE_COLOR;
var moveType = MOVE_NONE;
var touchType = "";
var editNeedRender = true;
var editNeedRender2 = true;
var sendLevel = false;
var lastSendLevel = undefined;
var sendLevel2 = false;
var sendSat = false;
var sendHue = false;
var sendColorTemp = false;
var touch0 = { x: 0, y: 0 };
var touch0Prev = { x: 0, y: 0 };

var colorPos = { x: 0, y: 0 };

// relative width of dimm and color secions
var dimmWidth = 0.2;
var dimmHeight = 0.45;
var colorWidth = 0.3;
var colorHeight = 0.52;
var colorMapHeight = 100;
var hueHeight = 800; // high of hue image
// canvas color kongfu
var colorCanvas = undefined;
var colorCtx = undefined;
var pageEditWidth = undefined;
var pageEditHeight = undefined;

// touch handler
var editHammer = undefined;
var sendCheckerActive = false;
var sendCheckTimer = undefined;

var rafID = 0; // because this shall be a non-zero value

function lightEditReset() {
    console.log("light edit reset");
    moveType = MOVE_NONE;
    lastSendLevel = undefined;
    sendLevel = false;
    sendLevel2 = false;
    sendSat = false;
    sendHue = false;
    sendColorTemp = false;
}

function sendCheck() {
    sendCheckTimer = undefined;

    if (!isSending) {
        sendState();
    }

    if (sendCheckerActive) {
        sendCheckTimer = setTimeout(sendCheck, 1000);
    }
}

function stopSendCheck() {
    sendCheckerActive = false;
    if (sendCheckTimer !== undefined) {
        clearTimeout(sendCheckTimer);
        sendCheckTimer = undefined;
    }
}

function sendState() {
    if (sendLevel || sendSat || sendHue || sendColorTemp) {
        var out = { };
        out.type = curEdit.obj.type;
        out.id = curEdit.obj.id;
        out.transitiontime = MAX_TRANSITION_TIME;

        // send level to device
        if (sendLevel) {
            sendLevel = false;
            out.on = curEdit.obj.state.on;
            out.bri = curEdit.level;
			if (out.bri == 0) {
				$('#colorLoopBtn').text('Start Color Loop');
				$('#colorLoopBtn').removeClass('colorLoopShadow');
			}
            if (out.on === false) {
                $('#barLevelBig').css('background-color','#A1A1A1');
				if (out.type == 2) {
					changeRulesStatus("disabled", out.id);
				}
            } else {
                $('#barLevelBig').css('background-color','#ffffff');
				if (out.type == 2) {
					changeRulesStatus("enabled", out.id);
				}
            }

            // the transition time should be relative to the difference of the last level
            if (!sendSat && !sendHue && !sendColorTemp) {
                if (lastSendLevel !== undefined) {
                    var diff = Math.abs(lastSendLevel - out.bri);
                    if (diff >= 0 && diff <= 255) {
                        diff /= 255;
                        out.transitiontime = Math.max(1, Math.floor(diff * MAX_TRANSITION_TIME));
                        // console.log("level diff " + diff + " tt " + out.transitiontime);
                    }
                }
            }

            lastSendLevel = curEdit.level;
        }

        if (sendHue || sendSat) {
            var rgb = HSVtoRGB(curEdit.hue, curEdit.sat / 255, curEdit.levelPercent / 100);
            out.xy = rgbToXy(rgb[0], rgb[1], rgb[2]);
        }

        if (sendSat) {
            sendSat = false;
            out.sat = curEdit.sat;
        }

        if (sendHue) {
            sendHue = false;
            out.hue = Math.floor(curEdit.hue * 360.0 * 182.0444);
        }

        if (sendColorTemp) {
            sendColorTemp = false;
            out.ct = curEdit.ct;
        }

        pushObjState(out);
    }

    if (sendLevel2 && (curEdit2.obj !== undefined)) {
        var out2 = { };
        out2.type = curEdit2.obj.type;
        out2.id = curEdit2.obj.id;
        out2.on = curEdit2.obj.state.on;
        out2.bri = curEdit2.level;
        out2.transitiontime = MAX_TRANSITION_TIME;

        sendLevel2 = false;

        if (out2.on === false) {
            $('#barLevelBig2').css('background-color','#A1A1A1');
        } else {
            $('#barLevelBig2').css('background-color','#ffffff');
        }
		
		if (multiIds !== null && multiIds.length > 0) {
			var len = multiIds.length;
			for (var i = 0; i < len; ++i) {
				out2.id = multiIds[i];
				pushObjState(out2);
			}
		} else {
			pushObjState(out2);
		}
    }	
}

function setObjName(input) {
    var putUrl;
    var out = {};

    if (input.value === undefined) {
        console.log("no valid input field");
        return;
    }

    out.name = input.value;

    if (curEdit.obj.type === TYPE_LIGHT) {
        putUrl = '/api/' + apikey + '/lights/' + curEdit.obj.id;
    }
    else if (curEdit.obj.type === TYPE_GROUP) {
        putUrl = '/api/' + apikey + '/groups/' + curEdit.obj.id;
    }

    $.ajax({
        url: putUrl,
        type: 'PUT',
        cache: false,
        contentType: 'application/json; charset=utf-8',
        data: JSON.stringify(out),
        dataType: 'json',
        success: function(data) {
            console.log("renamed to " + out.name);
        },
        error: function(jqXHR, textStatus, errorThrown) {
            console.log("textStatus:", textStatus + ' ' + errorThrown);
            console.log(jqXHR.responseText);
        },
        timeout: 10000
    });
}

// Support iOS virtual keyboard "done" button
function onLightEditBlur(e) {
    if (e.target.nodeName === "INPUT") {
        setObjName(e.target);
    }
}

// Desktop and Android enter key
function onLightEditKeyup(e) {
    if (e.keyCode === 13) { // enter
        if (e.target.nodeName === "INPUT") {
            e.target.blur();
            //setObjName(e.target); // will be handled by blur handler
        }
    }
}

/**
 * Prevent bounce effect then scrolling the top/bottom parts on a mobile device.
 */
function initPreventBouncing() {
    // pageLightEdit only takes 2/3 of the whole screen
    // prevent bouncing if touch dragging in the footer area
    if (Modernizr.touch) {
        document.addEventListener('touchstart', function(e) {
            if (e.changedTouches[0].pageY > pageLightEdit.clientHeight) {
                e.preventDefault();
            }
        });

        document.addEventListener('touchmove', function(e) {
            if (e.changedTouches[0].pageY > pageLightEdit.clientHeight) {
                e.preventDefault();
            }
        });
    }
}

function initEditPage() {

    initPreventBouncing();
    //colorCanvas = document.createElement('canvas');
    //colorCtx = colorCanvas.getContext('2d');
    pageEditWidth = pageLightEdit.clientWidth;

    // touch handler
    editHammer = new Hammer(pageLightEdit, {
        drag_min_distance: 1,
        prevent_default: true,
        swipe: false,
        drag_horizontal: false,
        transform: false,
        hold: false
    });

    editHammer.ontap = function(e) {
      var el = e.originalEvent.target;
      var action = $(el).data("action");

      if (el.nodeName == 'INPUT') {
        el.focus();
        return true;
      }

      if (el.parentNode.id === 'satStateLabel' || el.parentNode.id === 'btn-group-color-temp') {
        if (colorEditMode === EDIT_MODE_COLOR) {
			$('.sat_ctrl').removeClass('active');
			$('.sat_ctrl').addClass('not_reachable');
			$('.temp_ctrl').removeClass('not_reachable');
			$('.temp_ctrl').addClass('active');	
            switchColorEditMode(EDIT_MODE_COLOR_TEMPERATURE);
        }
        else if (colorEditMode === EDIT_MODE_COLOR_TEMPERATURE) {
			$('.sat_ctrl').removeClass('not_reachable');
			$('.sat_ctrl').addClass('active');
			$('.temp_ctrl').removeClass('active');
			$('.temp_ctrl').addClass('not_reachable');	
            switchColorEditMode(EDIT_MODE_COLOR);
        }
      }
	  
	  if (el.parentNode.id === 'levelStateLabel' || el.parentNode.id === 'btn-group-lvl') {
		  if ((groupId === null && multiId !== null) || (multiIds !== null && multiIds.length > 0)) {
			  if ($('.rgb_lvl').hasClass('active')) {
				  $('.rgb_lvl').removeClass('active');
				  $('.rgb_lvl').addClass('not_reachable');
				  $('.white_lvl').removeClass('not_reachable');
				  $('.white_lvl').addClass('active');
				  renderLevel2();
			  } else {
				  $('.rgb_lvl').removeClass('not_reachable');
				  $('.rgb_lvl').addClass('active');
				  $('.white_lvl').removeClass('active');
				  $('.white_lvl').addClass('not_reachable');
				  renderLevel();
			  }
		  }
	  }
		
      if (el.id === 'colorLoopBtn') {
  		  if ( $('#colorLoopBtn').text() == "Start Color Loop") {
			  $('#selectColorLoopSpeedModal').modal('show');
		  } else {
			  activateColorloop(0);
			  $('#colorLoopBtn').text('Start Color Loop');
			  $('#colorLoopBtn').removeClass('colorLoopShadow');
		  }		  
	  }
		
      if (el.nodeName == 'A') {
        // stopSendCheck();

        if (Modernizr.sessionstorage) {
            // update config object and put into localsession storage
            if (typeof(config) === 'object') {
                if (lightId && (lightId in config.lights)) {
                    config.lights[lightId].on = curEdit.obj.state.on;
                    config.lights[lightId].hue = curEdit.obj.state.hue;
                    config.lights[lightId].bri = curEdit.obj.state.bri;
                    config.lights[lightId].sat = curEdit.obj.state.sat;
                    config.lights[lightId].ct = curEdit.obj.state.ct;
                    sessionStorage.config = JSON.stringify(config);
                }
            }
        }

        setTimeout(function() {
            location.assign(el.href);
        }, 100);
        return true;
      }

      if (action !== undefined) {
          if (action === "close") {
              stopSendCheck();
              location.href = '/'; // go back but reload dynamic data
          }
      }

      e.originalEvent.preventDefault();
    };

    editHammer.ondoubletap = function(e) {
        e.originalEvent.preventDefault();
    };

    editHammer.ondragend = function(e) {
        touchType = e.originalEvent.type;
        touch0Prev.x = touch0.x;
        touch0Prev.y = touch0.y;

        editNeedRender = true;
        e.originalEvent.preventDefault();
    };

    editHammer.onrelease = function(e) {
        var el = e.originalEvent.target;
        touchType = e.originalEvent.type;
        editNeedRender = true;
        setIsEditing(false);
        moveType = MOVE_NONE;

        if (el.nodeName == 'A') {
            return;
        }

        sendState();


        if (el !== devNameLabel) {
            e.originalEvent.preventDefault();
        }
    };

    editHammer.ondragstart = function(e) {
        if (Modernizr.touch) {
            touch0.x = e.originalEvent.changedTouches[0].pageX;
            touch0.y = e.originalEvent.changedTouches[0].pageY;
        }
        else {
            touch0.x = e.originalEvent.pageX;
            touch0.y = e.originalEvent.pageY;
        }
        touch0Prev.x = touch0.x;
        touch0Prev.y = touch0.y;

        setIsEditing(true);

        var x = touch0.x - pageLightEdit.offsetLeft;

        pageEditWidth = pageLightEdit.clientWidth;

        if (x <= pageEditWidth * 0.259) {
            moveType = MOVE_LEFT;
            // console.log('move saturation');
        }
        else if (x <= pageEditWidth * 0.630) {
            moveType = MOVE_COLOR;
            // console.log('move color');
        }
        else if (x <= pageEditWidth) {
            moveType = MOVE_LEVEL;
            // console.log('move level');
        }

        touchType = e.originalEvent.type;
        editNeedRender = true;
        e.originalEvent.preventDefault();
    };

    editHammer.ondrag = function(e) {
        touchType = e.originalEvent.type;
        if (Modernizr.touch) {
            touch0.x = e.originalEvent.changedTouches[0].pageX;
            touch0.y = e.originalEvent.changedTouches[0].pageY;
        }
        else {
            touch0.x = e.originalEvent.pageX;
            touch0.y = e.originalEvent.pageY;
        }
        editNeedRender = true;
        e.originalEvent.preventDefault();
    };
}

/**
 * Converts RGB to CIE 1931 xy values
 * All in- and outputs are in the range 0..1
 * @param  {Number} r red color.
 * @param  {Number} g green color.
 * @param  {Number} b blue color.
 * @returns {Array} The x and y coordinates [x,y].
 */
function rgbToXy(r, g, b) {

   var X = 0.412453 * r + 0.357580 * g + 0.180423 * b;
   var Y = 0.212671 * r + 0.715160 * g + 0.072169 * b;
   var Z = 0.019334 * r + 0.119193 * g + 0.950227 * b;

   var x = X / (X + Y + Z);
   var y = Y / (X + Y + Z);
   return [ x, y ];
}

/**
 * Converts HSV to RGB
 * All in- and outputs are in the range 0..1
 * @param  {Number} h hue.
 * @param  {Number} s saturation.
 * @param  {Number} v value.
 * @returns {Array} The RGB array [r,g,b].
 */
function HSVtoRGB(h, s, v) {
    var r, g, b, i, f, p, q, t;

    i = Math.floor(h * 6);
    f = h * 6 - i;
    p = v * (1 - s);
    q = v * (1 - f * s);
    t = v * (1 - (1 - f) * s);
    switch (i % 6) {
        case 0: r = v, g = t, b = p; break;
        case 1: r = q, g = v, b = p; break;
        case 2: r = p, g = v, b = t; break;
        case 3: r = p, g = q, b = v; break;
        case 4: r = t, g = p, b = v; break;
        case 5: r = v, g = p, b = q; break;
    }
    return [r, g, b];
}

function rgb2hsv (r,g,b) {
 var computedH = 0;
 var computedS = 0;
 var computedV = 0;

 //remove spaces from input RGB values, convert to int
 var r = parseInt( (''+r).replace(/\s/g,''),10 );
 var g = parseInt( (''+g).replace(/\s/g,''),10 );
 var b = parseInt( (''+b).replace(/\s/g,''),10 );

 if ( r==null || g==null || b==null ||
     isNaN(r) || isNaN(g)|| isNaN(b) ) {
   return;
 }
 if (r<0 || g<0 || b<0 || r>255 || g>255 || b>255) {
   return;
 }
 r=r/255; g=g/255; b=b/255;
 var minRGB = Math.min(r,Math.min(g,b));
 var maxRGB = Math.max(r,Math.max(g,b));

 // Black-gray-white
 if (minRGB==maxRGB) {
  computedV = minRGB;
  return [0,0,computedV];
 }

 // Colors other than black-gray-white:
 var d = (r==minRGB) ? g-b : ((b==minRGB) ? r-g : b-r);
 var h = (r==minRGB) ? 3 : ((b==minRGB) ? 1 : 5);
 computedH = 60*(h - d/(maxRGB - minRGB));
 computedS = (maxRGB - minRGB)/maxRGB;
 computedV = maxRGB;
 return [computedH,computedS,computedV];
}

function calcColor() {
    var dx = touch0.x - touch0Prev.x;
    var dy = touch0.y - touch0Prev.y;

    touch0Prev.x = touch0.x;
    touch0Prev.y = touch0.y;

    colorPos.y += dy;

    var imgy = colorPos.y % hueHeight;

    if (imgy < 0) {
        imgy = hueHeight + imgy;
    }

    var pos = (hueHeight - imgy) / hueHeight;

    curEdit.hue = pos;

    if (curEdit.hue > 1)
      curEdit.hue = 1;
    else if (curEdit.hue < 0)
      curEdit.hue = 0;

    curEdit.obj.hue = curEdit.hue;
    curEdit.obj.state.hue = curEdit.hue * 360.0 * 182.0444;
}

// recalculate level based on dy of single finger drag
function calcLevel() {
//    var dx = touch0.x - touch0Prev.x;
    var dy = touch0.y - touch0Prev.y;

    touch0Prev.x = touch0.x;
    touch0Prev.y = touch0.y;

    if (dy !== 0) {
        var accel = 1.0;
        curEdit.levelPercent -= 100 * (dy * accel) / pageEditHeight;
    }

    if (curEdit.levelPercent < 0)
        curEdit.levelPercent = 0;
    else if (curEdit.levelPercent > 100)
        curEdit.levelPercent = 100;

    curEdit.level = Math.floor(curEdit.levelPercent / 100 * 255);

    if (curEdit.level < 0)
      curEdit.level = 0;
    else if (curEdit.level > 255)
      curEdit.level = 255;

    curEdit.obj.levelPercent = curEdit.levelPercent;
    curEdit.obj.level = curEdit.level;
    curEdit.obj.state.bri = curEdit.level;

    // check if level changed on/off state
    if (curEdit.level === 0) {
        curEdit.obj.state.on = false;
    }
    else {
        curEdit.obj.state.on = true;
    }

    sendLevel = true;
}

// recalculate level of multi-device white channel
function calcLevel2() {
//    var dx = touch0.x - touch0Prev.x;
    var dy = touch0.y - touch0Prev.y;

    touch0Prev.x = touch0.x;
    touch0Prev.y = touch0.y;

    if (dy !== 0) {
        var accel = 1.0;
        curEdit2.levelPercent -= 100 * (dy * accel) / pageEditHeight;
    }

    if (curEdit2.levelPercent < 0)
        curEdit2.levelPercent = 0;
    else if (curEdit2.levelPercent > 100)
        curEdit2.levelPercent = 100;

    curEdit2.level = Math.floor(curEdit2.levelPercent / 100 * 255);

    if (curEdit2.level < 0)
      curEdit2.level = 0;
    else if (curEdit2.level > 255)
      curEdit2.level = 255;

    curEdit2.obj.levelPercent = curEdit2.levelPercent;
    curEdit2.obj.level = curEdit2.level;
    curEdit2.obj.state.bri = curEdit2.level;

    // check if level changed on/off state
    if (curEdit2.level === 0) {
        curEdit2.obj.state.on = false;
    }
    else {
        curEdit2.obj.state.on = true;
    }

    sendLevel2 = true;
}

// recalculate level based on dy of single finger drag
function calcSaturation() {
//    var dx = touch0.x - touch0Prev.x;
    var dy = touch0.y - touch0Prev.y;

    touch0Prev.x = touch0.x;
    touch0Prev.y = touch0.y;

    if (dy !== 0) {
        var accel = 1.0;
        curEdit.satPercent -= 100 * (dy * accel) / pageEditHeight;
    }

    curEdit.sat = Math.floor(curEdit.satPercent / 100 * 255);

    if (curEdit.satPercent < 0)
        curEdit.satPercent = 0;
    else if (curEdit.satPercent > 100)
        curEdit.satPercent = 100;

    if (curEdit.sat < 0)
      curEdit.sat = 0;
    else if (curEdit.sat > 255)
      curEdit.sat = 255;

    curEdit.obj.satPercent = curEdit.satPercent;
    curEdit.obj.sat = curEdit.sat;
    curEdit.obj.state.sat = curEdit.sat;
}

// recalculate color temperature based on dy of single finger drag
function calcColorTemperature() {
    var ctMin = 153;
    var ctMax = 500;
    var dy = touch0.y - touch0Prev.y;

    touch0Prev.x = touch0.x;
    touch0Prev.y = touch0.y;

    if (dy !== 0) {
        var accel = 1.0;
        curEdit.ctPercent -= 100 * (dy * accel) / pageEditHeight;
    }

    if (curEdit.ctPercent < 0)
        curEdit.ctPercent = 0;
    else if (curEdit.ctPercent > 100)
        curEdit.ctPercent = 100;

    var norm = curEdit.ctPercent / 100;
    var ct = (norm * (ctMax - ctMin)) + ctMin;

    if (ct < ctMin)
      ct = ctMin;
    else if (ct > ctMax)
      ct = ctMax;
  
    curEdit.ct = ct;
    curEdit.obj.state.ct = ct;
}

function renderLevel() {
    if (curEdit.obj.state.on === false) {
        levelStateLabelValue.innerHTML = "Off";
        curEdit.levelPercent = 0;
    }
    var level = curEdit.levelPercent > 0 ? curEdit.levelPercent : 1;

    levelStateLabelValue.innerHTML = Math.floor(curEdit.levelPercent) + "%";

	var barLevelShd = $("#barLevelShd").height();
	
    barLevel.style["height"] = (barLevelShd * (level / 100)) + "px";
}

function renderLevel2() {
	if (curEdit2.obj !== undefined) {
		if (curEdit2.obj.state.on === false) {
			levelStateLabelValue.innerHTML = "Off";
			curEdit2.levelPercent = 0;
		}
		var level = curEdit2.levelPercent > 0 ? curEdit2.levelPercent : 1;

		levelStateLabelValue.innerHTML = Math.floor(curEdit2.levelPercent) + "%";

		var barLevelShd = $("#barLevelShd").height();
		
		barLevel.style["height"] = (barLevelShd * (level / 100)) + "px";
	}
}

function renderLeftBar() {
    var percent = 0;
    var label = 0;
    if (colorEditMode === EDIT_MODE_COLOR) {
        percent = curEdit.satPercent > 0 ? curEdit.satPercent : 1;
        label = curEdit.satPercent;
    }
    else if (colorEditMode === EDIT_MODE_COLOR_TEMPERATURE) {
        percent = curEdit.ctPercent > 0 ? curEdit.ctPercent : 1;   
        label = curEdit.ctPercent;
    }

    satStateLabelValue.innerHTML = Math.floor(label) + "%";
	
	var barSatShd = $("#barSatShd").height();
	
    barSat.style["height"] = (barSatShd * (percent / 100)) + "px";
}

function renderHue() {
    colorMap.style.backgroundPosition = Math.floor(colorPos.x) + "px " + Math.floor(colorPos.y) + "px";
}

function renderDimmEdit(t) {
    if (!editNeedRender) {
        cancelRequestAnimFrame(rafID);
        rafID = requestAnimationFrame(renderDimmEdit);
        return;
    }

    editNeedRender = false; // mark as rendered

    if ((moveType === MOVE_LEVEL) && ($('.white_lvl').hasClass('active')) && (curEdit2.obj !== undefined)) {
        calcLevel2();
        renderLevel2();
    } else if (moveType === MOVE_LEVEL) {
        calcLevel();
        renderLevel();
    }
    else if (moveType === MOVE_COLOR) {
        calcColor();
        if (colorEditMode === EDIT_MODE_COLOR) {
            sendSat = true;
            sendHue = true;
        }
        renderHue();
    }
    else if (moveType === MOVE_LEFT) {
    
        if (colorEditMode === EDIT_MODE_COLOR) {
            calcSaturation();
            sendSat = true;
            sendHue = true;
        }
        else if (colorEditMode === EDIT_MODE_COLOR_TEMPERATURE) {
            calcColorTemperature();
            sendColorTemp = true;
        }
        renderLeftBar();
    }

    cancelRequestAnimFrame(rafID);
    rafID = requestAnimationFrame(renderDimmEdit);
}

function adjustLevelEditPage() {
    if ($(pageLightEdit).hasClass('hidden')) {
        return;
    }

    var pageHeight = $(pageLightEdit).innerHeight();

    canvas0ClientWidth = 48;
    canvas0ClientHeight = Math.floor(pageHeight * dimmHeight);

    barLevel.style.bottom  = "40%";
    barLevel.style.right  = "36px";
    barLevel.style.height = "45%";

    // copy to shadow div
    var barLevelShd = document.getElementById('barLevelShd');
    barLevelShd.style.bottom = barLevel.style.bottom;
    barLevelShd.style.right = barLevel.style.right;
    barLevelShd.style.height = barLevel.style.height;
    barLevelShd.height = barLevel.height;

    barSat.style.bottom  = "40%";
    barSat.style.left  = "36px";
    barSat.style.height = "45%";

    // copy to shadow div
    var barSatShd = document.getElementById('barSatShd');
    barSatShd.style.bottom = barSat.style.bottom;
    barSatShd.style.left = barSat.style.left;
    barSatShd.style.height = barSat.style.height;
    barSatShd.height = barSat.height;

    canvasColorClientWidth = Math.floor(winInnerWidth * colorWidth);
    canvasColorClientHeight = Math.floor(winInnerHeight * colorHeight);
    canvasColorClientWidth = 30;
    canvasColorClientHeight = 50;

    colorMap.width  = canvasColorClientWidth;
    colorMap.height = canvasColorClientHeight;
    colorMap.style.top  = "15%";
    colorMap.style.left  = 35 + "%";
    colorMap.style.width  = canvasColorClientWidth + "%";
    colorMap.style.height = canvasColorClientHeight + "%";

    // footer fixed at the bottom
    //pageLightEdit.style.height = winInnerHeight + "px";

    //var footerWidth = footer.clientWidth;
    pageEditWidth = pageLightEdit.clientWidth;
    pageEditHeight = pageLightEdit.clientHeight;
    //footer.style.left = ((pageEditWidth / 2) - (footerWidth / 2)) + "px";
}

function lightEditSetHue(hue) {
  colorPos.y = hueHeight - (hueHeight * hue);
}

/**
 * Color edit mode switcher.
 * @param  {Number} mode the new color edit mode.
 */
function switchColorEditMode(mode) {
    colorEditMode = mode;
   
    if (colorEditMode === EDIT_MODE_COLOR) {
        colorMap.style.visibility = "";
        barSat.style.visibility = "";
        barSatShd.style.visibility = "";
        $('#satStateLabel')[0].style.visibility = "";
        $('#satStateLabel p').html('Sat');
		$('.temp_ctrl').removeClass('active');
		$('.temp_ctrl').addClass('not_reachable');
		$('.sat_ctrl').removeClass('not_reachable');
		$('.sat_ctrl').addClass('active');
    }
    else if (colorEditMode === EDIT_MODE_MONOCHROMATIC) {
        colorMap.style.visibility = "hidden";
        barSat.style.visibility = "hidden";
        barSatShd.style.visibility = "hidden";
        $('#satStateLabel')[0].style.visibility = "hidden";
		$('.sat_ctrl').removeClass('active');
		$('.sat_ctrl').addClass('not_reachable');
		$('.temp_ctrl').removeClass('active');
		$('.temp_ctrl').addClass('not_reachable');	
    }
    else if (colorEditMode === EDIT_MODE_COLOR_TEMPERATURE) {
        colorMap.style.visibility = "hidden";
        barSat.style.visibility = "";
        barSatShd.style.visibility = "";
        $('#satStateLabel')[0].style.visibility = "";
        $('#satStateLabel p').html('Temp');
		$('.temp_ctrl').removeClass('not_reachable');
		$('.temp_ctrl').addClass('active');
		$('.sat_ctrl').removeClass('active');
		$('.sat_ctrl').addClass('not_reachable');
    }
}

function showLightEditPage() {
  $(document.body).addClass("darkBg");
  $(pageLightEdit).removeClass("pageHide");
  winInnerWidth = window.innerWidth;
  winInnerHeight = window.innerHeight;
  moveType = MOVE_NONE;

  detectVendorPrefixes();

  curPage = pageLightEdit;

  var hue = 0;

  if (curEdit.obj.state.hue) {
    hue = curEdit.obj.state.hue / 182.04444;
    hue = hue / 360;
    if (hue < 0) {
        hue = 0;
    }
    else if (hue > 1) {
        hue = 1;
    }
    curEdit.obj.hue = hue;
  }

  lightEditSetHue(hue);
  colorMap.style.backgroundPosition = colorPos.x + "px " + colorPos.y + "px";
  colorMapHeight = colorMap.clientHeight;

  sendLevel = false;
  sendLevel2 = false;
  sendSat = false;
  sendHue = false;
  sendColorTemp = false;
  devNameLabel.value = curEdit.obj.name;
  curEdit.levelPercent = curEdit.obj.levelPercent;
  if (curEdit2.obj != undefined) {
	curEdit2.levelPercent = curEdit2.obj.levelPercent;
  }
  curEdit.satPercent = curEdit.obj.satPercent;
  curEdit.ctPercent = curEdit.obj.ctPercent;
  curEdit.hue = curEdit.obj.hue;
  curEdit.sat = curEdit.obj.state.sat;

  var mode = EDIT_MODE_COLOR;

  if (curEdit.obj.state.colormode == 'ct') {
      mode = EDIT_MODE_COLOR_TEMPERATURE;
  }
  else if (curEdit.obj.modelid && curEdit.obj.modelid.indexOf("FLS-H") != -1) {
      mode = EDIT_MODE_COLOR_TEMPERATURE;
  }
  else if (!curEdit.obj.hasColor) {
      mode = EDIT_MODE_MONOCHROMATIC;
  }

  switchColorEditMode(mode);

  editNeedRender = true;
  renderLevel();
  renderHue();
  renderLeftBar();

  cancelRequestAnimFrame(rafID);
  rafID = requestAnimationFrame(renderDimmEdit);

  $(colorMap).removeClass('colorMapHidden');

    document.addEventListener("blur", onLightEditBlur, true);
    document.addEventListener("keyup", onLightEditKeyup, true);

    sendCheckerActive = true;
    sendCheck();
    devNameLabel.blur();

	if (curEdit.obj.hasColor && curEdit.obj.state.colormode !== "ct") {
		$('#colorLoopDiv').removeClass('hidden');
		if (curEdit.obj.state.effect === "colorloop") {
			$('#colorLoopBtn').text('Stop Color Loop');
			$('#colorLoopBtn').addClass('colorLoopShadow');
		} else {
			$('#colorLoopBtn').text('Start Color Loop');
			$('#colorLoopBtn').removeClass('colorLoopShadow');
		}
	} else {
	    $('#btn-group-color-temp').addClass('hidden');
	}
			
    // hide url bar
    setTimeout(function () {
        window.scrollTo(0, 1);
    }, 10);
}

function hideLightEditPage() {
    sendCheckerActive = false;
    $(document.body).removeClass("darkBg");
    sendLevel = false;

    $(pageLightEdit).addClass("pageHide");
  //document.removeEventListener('touchstart', editOnTouchStart);
  //document.removeEventListener('touchend', editOnTouchEnd);
  //document.removeEventListener('touchmove', editOnTouchMove);
    document.removeEventListener("blur", onLightEditBlur, true);
    document.removeEventListener("keyup", onLightEditKeyup, true);
}

function activateColorloop(speed) {
  var params = "";
  var putUrl = "";
  
  if (speed == 0) {
      params = '{"effect":"none"}';
  } else {
      params = '{"effect":"colorloop","colorloopspeed":' + speed + '}';
  }
  
  if (lightId !== null) {
	  putUrl = '/api/' + apikey + '/lights/' + lightId + '/state';
  } else {
	  putUrl = '/api/' + apikey + '/groups/' + groupId + '/action';
  }

  $.ajax({
        url: putUrl,
        type: 'PUT',
        contentType: 'application/json; charset=utf-8',
        data: params,
        dataType: 'json',
        cache: false,
        headers: { 'Accept': apiversion },
        success: function(data) {

        },
        error: function(jqXHR, textStatus, errorThrown) {
            console.log("textStatus:", textStatus + ' ' + errorThrown);
            console.log(jqXHR.responseText);
            console.log("sending state failed");
        },
        timeout: 8000
    });
}
