var PEffectControl = Class.create({
    CLASSDEF: {
        name: 'PEffectControl'
    },
  
  initialize: function PEC_initialize(caption, code, effect, props, callback, iId) {
    this.caption = caption;
    this.code = code;
    this.effect = effect;
    this.props = props;
    this.id = effect[0] + "_" + code + "_" + iId;
    this.callback = callback;
  },
  
  buildHTML: function PEC_buildHTML() {
    return  '<label>'+this.caption+'</label>'+this.buildControlHTML();
  },
  
  bindControls: function PEC_bindControls() {
    
  },
  
  remove: function PEC_remove() {
    
  },
  
  loadFromState: function PEC_loadFromState(state) {
    
  },
  
  saveToState: function PEC_saveToState(state) {
    
  },
  
  validateInput: function PEC_validateInput(inputEl, defaultVal,callback) {
    if(inputEl.value=="") {
      inputEl.value = defaultVal;
      log("fixing input (blank)");
      callback();
    } else if(parseInt(inputEl.value, 10)==NaN) {
      inputEl.value = defaultVal;
      log("fixing input (NaN)");
      callback();
    } else if(parseInt(inputEl.value, 10)!=inputEl.value) {
      log("fixing input (neq)");
      inputEl.value = defaultVal;
      callback();
    }
  },
  
  onChanged: function PEC_onChanged() {
    this.callback();
  }
});

var PTextboxControl = Class.create({
    CLASSDEF: {
        name: 'PTextboxControl',
    parent: PEffectControl
    },
  
  initialize: function PTC_initialize(caption, code, effect, props, callback, iId) {
    PTextboxControl.parentClass.constructor().call(this,caption, code, effect, props, callback, iId);
  },
  
  buildControlHTML: function PTC_buildControlHTML() {
    var size = "1";
    if(this.props["s"]!=null) {
      size = this.props["s"];
    }
    return "<input type=\"text\" class=\"effectspanelfield\" name=\"" + this.id + "_ctl\" size=\"" + size + "\" value=\"\" id=\"" + this.id + "\" />";
    //return "<input name=\"" + this.id + "_ctl\" size=\"" + size + "\" value=\"" + def + "\" id=\"" + this.id "\"/>";
  },
  
  bindControls: function PTC_bindControls() {
    var _this = this;
    this.textbox = $(this.id);
    this.textbox.onkeyup = function() {
      _this.value = _this.textbox.value;
      _this.onChanged();
    };
  },
  
  loadFromState: function PTC_loadFromState(state, allowDefault) {
    var val = state[this.code];
    if(allowDefault && val == null) {
      val = this.props.d;
    }
    this.textbox.value = val;
  },
  
  saveToState: function PTC_saveToState(state) {
    state[this.code] = this.textbox.value;
  }
});

var PSliderControl = Class.create({
    CLASSDEF: {
        name: 'PSliderControl',
    parent: PEffectControl
    },
  
  initialize: function PSC_initialize(caption, code, effect, props, callback, iId) {
    PSliderControl.parentClass.constructor().call(this,caption, code, effect, props, callback, iId);
  },
  
  buildControlHTML: function PSC_buildControlHTML() {
	  return '<div id="' + this.id + '_t" style="width: 88px;" class="et_bar"><div id="' + this.id + '_s" style="" class="et_grab"> </div></div>';
  },
  
  bindControls: function PSC_bindControls() {
    var _this = this;
    this.slider = new Control.Slider(this.id + '_s',this.id + '_t', {
      range:this.props["r"],
      values:this.props["v"],
      sliderValue:this.props["d"],
      onChange: function PSC_onChange(v) {
        _this.slideValue = v;
        _this.onChanged();
      }
    });
  },
  
  loadFromState: function PSC_loadFromState(state, allowDefault) {
    var val = state[this.code];
    if(allowDefault && val == null) {
      val = this.props.d;
    }
    this.slideValue = val;
    this.slider.setValue(val);
  },
  
  saveToState: function PSC_saveToState(state) {
    state[this.code] = this.slideValue;
  },
  
  remove: function PSC_remove() {
    if(this.slider!=null) {
      this.slider.dispose();
      this.slider = null;
    }
  }
});

var PColorSliderControl = Class.create({
    CLASSDEF: {
        name: 'PColorSliderControl',
    parent: PSliderControl
    },
  
  initialize: function PCSC_initialize(caption, code, effect, props, callback, iId) {
    PColorSliderControl.parentClass.constructor().call(this,caption, code, effect, props, callback, iId);
  },
  
  buildControlHTML: function PCSC_buildControlHTML() {
    return '<div id="' + this.id + '_t" style="width:50px;background-color:#aaa;height:10px;background-image:url(' + d.pathPrefix + '/images/colors.gif);"><div id="' + this.id + '_s" style="width:3px;height:8px;cursor:e-resize;border:1px solid black;"> </div></div>';
  }
});
      
var PCheckboxControl = Class.create({
    CLASSDEF: {
        name: 'PCheckboxControl',
    parent: PEffectControl
    },
  
  initialize: function PCC_initialize(caption, code, effect, props, callback, iId) {
    PCheckboxControl.parentClass.constructor().call(this,caption, code, effect, props, callback, iId);
  },
  
  buildControlHTML: function PCC_buildControlHTML() {
    return '<input type="checkbox" class="effectspanelfield" name="' + this.id + '_ctl" value="1" id="' + this.id + '" />';
  },
  
  bindControls: function PCC_bindControls() {
    var _this = this;
    this.checkbox = $(this.id);
    this.checkbox.onclick = function() {
      if(_this.checkbox.checked) {
        _this.value = "1";
      } else {
        _this.value = "0";
      }
      _this.onChanged();
    };
  },
  
  loadFromState: function PCC_loadFromState(state, allowDefault) {
    this.value = state[this.code];
    if(allowDefault && this.value == null) {
      this.value = this.props.d;
    }
    if(this.value == "1") {
      this.checkbox.checked = true;
    } else {
      this.checkbox.checked = false;
    }
  },
  
  saveToState: function PCC_saveToState(state) {
    state[this.code] = this.value;
  }
});

var PSelectControl = Class.create({
    CLASSDEF: {
        name: 'PSelectControl',
    parent: PEffectControl
    },
  
  initialize: function PSBC_initialize(caption, code, effect, props, callback, iId) {
    PSelectControl.parentClass.constructor().call(this,caption, code, effect, props, callback, iId);
    this.value = "";
  },
  
  buildControlHTML: function PSBC_buildControlHTML() {
    var html = '<select id="' + this.id + '" class="et_effect_control_s">';
    var opts = this.props["v"];
    for(var i=0;i<opts.length;i++) {
      html += '<option value="' + opts[i][1] + '">' + opts[i][0] + '</option>';
    }
    html += '</select>';
    return html;
  },
  
  bindControls: function PSBC_bindControls() {
    this.select = $(this.id);
    this.setupListener();
  },
  
  setupListener: function PSBC_setupListener() {
    var _this = this;
    this.select.onchange = function() {
      _this.value = _this.select.value;
      _this.onChanged();
    };
  },
  
  loadFromState: function PSBC_loadFromState(state, allowDefault) {
    this.value = state[this.code];
    if(allowDefault && this.value == null) {
      this.value = this.props.d;
    }
    this.select.value = this.value;
  },
  
  saveToState: function PSBC_saveToState(state) {
    state[this.code] = this.value;
  }
});


var PRotateControl = Class.create({
    CLASSDEF: {
        name: 'PRotateControl',
    parent: PEffectControl
    },
  
  initialize: function PRC_initialize(caption, code, effect, props, callback, iId) {
    PRotateControl.parentClass.constructor().call(this,caption, code, effect, props, callback, iId);
  },
  
  buildControlHTML: function PRC_buildControlHTML() {
    this.value = 0;
    if(this.props["d"]!=null) {
      this.value = this.props["d"];
    }
    return '<div style="position:relative;width:36px;height:36px;" id="' + this.id + '_co"><img style="position:absolute;top:0px;left:0px;" src="/images/mp/circle_with_line.gif" id="' + this.id + '_c" border="0" style="margin-bottom:0px;" align="absmiddle"/></div>';
  },
  
  bindControls: function PRC_bindControls() {
    
    var _this = this;
    
    this.rotateContainer = $(this.id + "_co");
    this.rotateImg = $(this.id + "_c");
    this.rotateImg.style.cursor = "pointer";
  
    
    this.rotateWidget = new  RotateWidget(this.rotateContainer, this.rotateImg, null, null, function(d) {
        log("PRotateControl.changed");
      _this.value = d;
      _this.onChanged();
    });
  },
  
  loadFromState: function PRC_loadFromState(state, allowDefault) {
    this.value = state[this.code];
    if(allowDefault && this.value == null) {
      this.value = this.props.d;
    }
    this.rotateWidget.setValue(parseInt(this.value, 10));
  },
  
  saveToState: function PRC_saveToState(state) {
    state[this.code] = this.value;
  },
  
  remove: function PRC_remove() {
    if(this.rotateWidget!=null) {
      this.rotateWidget.del();
    }
  }
});


var RotateWidget = Class.create({
    CLASSDEF: {
        name: 'RotateWidget'
    },
  
  initialize: function RW_initialize(container, rotationWidget, l, r, t, callback) {
    this.container = container;
    this.rotationWidget = rotationWidget;
    this.l = l;
    this.r = r;
    this.t = t;
    this.callback = callback;
    
    this.rotCanvas = document.createElement("DIV");
    this.rotCanvas.id = "rw_" + d.getNextId();
    //this.rotCanvas.style.position = "absolute";
    //this.rotCanvas.style.width = "66px";
    //this.rotCanvas.style.height = "50px";
    this.container.appendChild(this.rotCanvas);
    this.jg = new jsGraphics(this.rotCanvas);
    
    
    
    
    this.rWidth = 36;//this.rotationWidget.width;
    this.rHeight = 36;//this.rotationWidget.height;
    
    this.rOffsetX = parseInt(this.rotationWidget.style.left, 10) -1;
    this.rOffsetY = parseInt(this.rotationWidget.style.top, 10) - 1;
    
    this.eventStartRotation =  this.startRotation.bindAsEventListener(this);
    this.eventRotateMove =  this.rotateMove.bindAsEventListener(this);
    this.eventRotateFinish =  this.rotateFinish.bindAsEventListener(this);
    Event.observe(this.rotationWidget, "mousedown", this.eventStartRotation);
    
    this.handle = document.createElement("IMG");
    this.handle.src = "/ppr/images/sizer.gif";
    this.handle.id = "rwh_" + d.getNextId();
    this.handle.style.position = "absolute";
    this.handle.style.cursor="pointer";
    this.handle.style.top = (this.rOffsetY - 3) + "px";
    this.handle.style.left = (this.rOffsetX + this.rWidth/2 - 3) + "px";
    this.handle.style.zIndex = 2999; // below 3000 so popup goes above it
    this.container.appendChild(this.handle);
    
    Event.observe(this.handle, "mousedown", this.eventStartRotation);
    
    
    if(l!=null) {
      this.rotateLeftClickEvent = this.rotateLeftClick.bindAsEventListener(this);
      this.rotateDblLeftClickEvent = this.rotateDblLeftClick.bindAsEventListener(this);
      Event.observe(this.l, "click", this.rotateLeftClickEvent);
      Event.observe(this.l, "dblclick", this.rotateDblLeftClickEvent);
    }
    
    if(r!=null) {
      this.rotateRightClickEvent = this.rotateRightClick.bindAsEventListener(this);
      this.rotateDblRightClickEvent = this.rotateDblRightClick.bindAsEventListener(this);
      Event.observe(this.r, "click", this.rotateRightClickEvent);
      Event.observe(this.r, "dblclick", this.rotateDblRightClickEvent);
    }
    if(t != null) {
      this.rotateTxtKeyUp = this.rotateTxtKeyUp.bindAsEventListener(this);
      Event.observe(this.t, "keyup", this.rotateTxtKeyUp);
      Event.observe(this.t, "blur", this.rotateTxtKeyUp);
    }
    
    
    this.zeroRotImage = true;
    
    this.value = 0;
    
    
  },
  
  del: function RW_del() {
    if(this.rotationWidget != null) {
      Event.stopObserving(this.rotationWidget, "mousedown", this.eventStartRotation);
      
      if(this.rotateDblLeftClickEvent!=null) {
        Event.stopObserving(this.l, "click", this.rotateLeftClickEvent);
        Event.stopObserving(this.l, "dblclick", this.rotateDblLeftClickEvent);
      }
      if(this.rotateDblRightClickEvent!=null) {
        Event.stopObserving(this.r, "click", this.rotateRightClickEvent);
        Event.stopObserving(this.r, "dblclick", this.rotateDblRightClickEvent);
      }
      if(this.rotateTxtKeyUp!=null) {
        Event.stopObserving(this.t, "keyup", this.rotateTxtKeyUp);
        Event.stopObserving(this.t, "blur", this.rotateTxtKeyUp);
      }
    }
  },
  
  startRotation: function RW_startRotation(event) {
    log("start rotation");
    Event.stop(event);
    //start tracking mouse movement
    Event.observe(document, "mousemove", this.eventRotateMove);
    Event.observe(document, "mouseup", this.eventRotateFinish);
    
    //store the current location of the rotation widget center
  
    var pos = Position.cumulativeOffset(this.rotationWidget);
    this.rotXPos = pos[0] + this.rWidth/2;
    this.rotYPos = pos[1] + this.rHeight/2;
    
    return true;
  },
  
  rotateMove: function RW_rotateMove(event) {
    //determine the angle from center of rotation widget to the mouse
    Event.stop(event);

    //first get size of the sides
    var mxPos = Event.pointerX(event);
    var myPos = Event.pointerY(event);
    
    var side1 = parseFloat(mxPos - this.rotXPos); //horiz
    var side2 = parseFloat(myPos - this.rotYPos); //vert
    var side3 = Math.sqrt((side1*side1) + (side2*side2)); //slope
    
    var offset = 0;
    if(side2 < 0) { //above
      if(side1 < 0) { //left
        offset = 270;
      } else { //right
        offset = 90;
      }
    } else { //below
      if(side1 < 0) { //left
        offset = 270;
      } else { //right
        offset = 90;
      }
    }
    
    var rads = Math.atan(side2/side1);
    var degs = this.radToDeg(rads);
    
    //round to closest 1 deg
    
    degs = parseInt(degs, 10);

    this.value = degs + offset;
    this.displayRotation(this.value, false, false);
    return true;
    //window.status = "wx=" + this.rot_x_pos + " wy=" + this.rot_y_pos + "mx=" + mxPos + " my=" + myPos + " side1=" + side1 + " side2=" + side2 + " rads=" + rads + " degs=" + degs; 
     
  },
  
  setValue: function RW_setValue(angle) {
    this.value = parseFloat(parseInt(angle, 10));
    this.displayRotation(angle,true,true);
  },
  
  displayRotation: function RW_displayRotation(angle, calc_center, finished) {
    angle = parseFloat(parseInt(angle, 10));
    if(this.jg==null) {
      return;
    }
    if(this.t != null) {
      this.t.value = angle;
    }
    
    
    if(calc_center) {
      var pos = Position.cumulativeOffset(this.rotationWidget);
      this.rotXPos = pos[0] + this.rWidth/2;
      this.rotYPos = pos[1] + this.rHeight/2;
    }
    
    


    rotXPos = this.rOffsetX + this.rWidth/2;
    rotYPos = this.rOffsetY + this.rHeight/2;
    
    //we know the center point (rot_?_pos), the elevation (angle) and the length (this.rotation_widget.width/2)...
    var length = this.rWidth/2 - 2;
    if(this.zeroRotImage) {
      //if(this.rotation_widget.src != pp.path_prefix + d.pathPrefix + "/images/circle_without_line.gif") {
      this.zeroRotImage = false;
      this.rotationWidget.src =  d.pathPrefix + "/images/mp/rotate_circle.png";
    }
    
    var rads = this.degToRad(angle - 90);
    
    //sin ? = opp / hyp ... opp = sin ? * hyp
    var y = Math.sin(rads) * length;
    //cos ? = adj / hyp ... adj = cos ? * hyp
    var x = Math.cos(rads) * length;
    
    this.handle.style.left = (x + rotXPos - 3) + "px";
    this.handle.style.top = (y + rotYPos - 3) + "px";
    
    if((finished) && (angle==0)) {
      this.jg.clear();
      this.rotationWidget.src = d.pathPrefix + "/images/mp/rotate_circle_with_line.png";
      this.zeroRotImage = true;
      return;
    }
    
    //draw a line using the supplied angle from the center to the rotation widget to the circle
    this.jg.clear();
    
    this.jg.setZIndex(2998);
    
    //this.jg.drawEllipse(x + this.rot_x_pos - 5, y + this.rot_y_pos -5, 10,10);
    this.jg.setStroke(1);
    this.jg.setColor("#777777");
    //this.jg.setColor("#FF0000");
    
    //log("drawLine(" + angle + ":" + (rotXPos + 1) + "," +  (rotYPos + 1) + "," +  (x + rotXPos + 1) + "," + (y + rotYPos+ 1) + ");");
    
    this.jg.drawLine(rotXPos + 1, rotYPos + 1, x + rotXPos + 1, y + rotYPos+ 1);
    this.jg.paint();
    
    
    
    
    //log(this.container.innerHTML);
    
  },
  
  degToRad: function (angle) {
    return ((angle*Math.PI) / 180.0);
  },

  radToDeg: function RW_radToDeg(angle) {
    return ((angle*180.0) / Math.PI);
  },
  
  rotateFinish: function RW_rotateFinish(event) {
    Event.stopObserving(document, "mousemove", this.eventRotateMove);
    Event.stopObserving(document, "mouseup", this.eventRotateFinish);
    this.displayRotation(this.value, false, true);
    this.callback(this.value);
    //d.itemChanged(true);
  },
  
  rotateLeftClick: function RW_rotateLeftClick(event) {
    this.doRotate(-5.0);
  },
  
  rotateRightClick: function RW_rotateRightClick(event) {
    this.doRotate(5.0);
  },
  
  rotateDblLeftClick: function RW_rotateDblLeftClick(event) {
    this.doRotate(-10.0);
  },
  
  rotateDblRightClick: function RW_rotateDblRightClick(event) {
    this.doRotate(10.0);
  },
  
  doRotate: function RW_doRotate(amount) {
    this.value += amount;
    //round to 5 deg
    this.value = parseFloat(parseInt(this.value / 5, 10)) * 5.0;
    if(this.value < 0) {
      this.value += 360;
    } else if(this.value >= 360) {
      this.value -= 360;
    }
    this.displayRotation(this.value, false, true);
    this.callback(this.value);
    //d.itemChanged(true);
  },
  
  rotateTxtKeyUp: function(event) {
    if(!isNaN(parseInt(this.t.value, 10))) {
      this.value = parseFloat(parseInt(this.t.value, 10));
      this.displayRotation(this.value, false, true);
      this.callback(this.value);
    }
  }
  
  
});


var controlClasses = {
  "S": PSliderControl,
  "CS": PColorSliderControl,
  "T": PTextboxControl,
  "R": PRotateControl,
  "CB": PSelectControl,
  "CH" : PCheckboxControl
};
