var Item = Class.create({
  CLASSDEF: {
      name: 'Item'
  },
  
  initialize: function Item_initialize(id, cViewProcess, asset, options) {
    this.id = id;
    this.asset = asset;
    this.options = options;
    this.enabled = true;
    this.setLocked(dopt(options, "lk", "false") == "true");
    this.cViewProcess = cViewProcess;
    this.cViewArea = cViewProcess.configuredViewArea;
    this.cView = this.cViewArea.configuredView;
    this.ready = false;
    
    this.isWilcomEMB = (options.emb == "1");
    this.isSavedDigitized = (this.asset.digitizedState > 1);
    this.stitchCount = options.stc;
    
    this.elId = this.cView.configuredProduct.id + "_" + this.id;
    
    this.reRender = false;
    this.renderVersion = (options.rv == null) ? 0 : options.rv;
    
    this.allowHandleResizing = true;
    
    this.managePaneBound = false;
    if(options.z) {
      this.zIndex = options.z;
    } else {
      this.zIndex = this.cViewProcess.getNextZOrder();
    }
    
    if((this.options.l)&&(this.options.t)&&(this.options.w)&&(this.options.h)) { //options contains positioning data
      this.height = parseFloat(this.options.h);
      this.width = parseFloat(this.options.w);
      this.left = parseFloat(this.options.l);
      this.top = parseFloat(this.options.t);
    } else if(!this.startPosition()) { //the derived object doesnt have special start positon logic (Text)
      var w =  this.cViewProcess.productProcess.fullWidth;
      var h = this.cViewProcess.productProcess.fullHeight;
      if(this.options.w == null) {
        if((this.isWilcomEMB)||(this.isSavedDigitized)) {
          this.height = parseInt(this.asset.height, 10);
          this.width = parseInt(this.asset.width, 10);
        } else {
          //auto position
          //by default this will position itself in the largest centered position allowed.
          log("rW=" + w + ", rH=" + h);
          var dims = this.asset.scale(h,w);
          dims = this.minDims(dims);
          this.maintainAspect = true;
          this.height = parseInt(dims.h, 10);
          this.width = parseInt(dims.w, 10);
        }
      } else {
        //does have size data (no position)
        this.height = parseFloat(this.options.h);
        this.width = parseFloat(this.options.w);
      }
      this.top = (h - this.height) / 2;
      this.left = (w - this.width) / 2;
    }
    
    this.deleteClickEvent = this.deleteClick.bindAsEventListener(this);
    this.zDownClickEvent = this.zDownClick.bindAsEventListener(this);
    this.zUpClickEvent = this.zUpClick.bindAsEventListener(this);
    
    this.eventResizeStart =  this.resizeStart.bindAsEventListener(this);
    this.eventResizeMouseUp =  this.resizeFinished.bindAsEventListener(this);
    this.eventResizeMouseMove =  this.resizeMove.bindAsEventListener(this);
    
    this.eventMouseDown =  this.mouseDown.bindAsEventListener(this);
    
    this.eventLockToggle = this.lockToggle.bindAsEventListener(this);
    
    this.isLastZ = false;
    this.isFirstZ = false;
    this.qualityOK = true;
    
    if(options.ar == null) {
      if( (this.width / this.height) ==  this.asset.aspectRatio) {
        this.maintainAspect = true;
      } else {
        this.maintainAspect = false;
      }
    } else {
      this.maintainAspect = (options.ar == "1");
    }
    this.allowResize = true;
    
    this.alerts = [{},{},{}]; //array of alerts: error/warning/notice
    
    this.canModifyDesign = this.cViewProcess.productProcess.canModifyDesign();
  },
  
  compare: function Item_compare(other) {
    return this.zIndex - other.zIndex;
  },
  
  beforeAddNew: function Item_beforeAddNew() {
    return false;
  },
  
  continueAdd: function Item_continueAdd() {
    
  },
  
  initialiseManagePane: function Item_initialiseManagePane() {
    var self = this;
    log("Item.initialiseManagePane()");
    this.cViewProcess.buildManagePane(this);
    this.managePane = $("mp1_" + this.elId);
    this.titleThumb = $("mp1_" + this.elId + "_stimg");
    
    var sizes = this.asset.scale(15,20);
    
    setTransPng(this.titleThumb, this.asset.url, parseInt(sizes.w, 10), parseInt(sizes.h, 10));
    //this.titleThumb.src = this.asset.url;
    //this.titleThumb.width = parseInt(sizes.w, 10);
    //this.titleThumb.height = parseInt(sizes.h, 10);
    
    this.titleBar = $("mp1_" + this.elId + "_bar");
    this.titleBar.onclick = function(ev) { self.select(); };
    
    this.titleSpan = $("mp1_" + this.elId + "_title");
    
    this.titleSize = $("mp1_" + this.elId + "_dim_value");
    this.initFeature("dim");
    this.updateTitleSize();
    
    this.titleZUp = $("mp1_" + this.elId + "_zup");
    Event.observe(this.titleZUp, "click", this.zUpClickEvent);
    this.titleZUp.style.cursor = "pointer";
    
    this.titleZDown = $("mp1_" + this.elId + "_zdown");
    Event.observe(this.titleZDown, "click", this.zDownClickEvent);
    this.titleZDown.style.cursor = "pointer";
    
    this.titleDel = $("mp1_" + this.elId + "_remove");
    Event.observe(this.titleDel, "click", this.deleteClickEvent);
    this.titleDel.style.cursor = "pointer";
    
    if(!this.canModifyDesign) {
      this.titleDel.hide();
    }
    
    this.lockContainer = $("mp1_" + this.elId + "_lock_container");
    this.lockCheckBox = $("mp1_" + this.elId + "_lock");
	this.lockIcon=$("mp1_"+this.elId+"_lock_icon");
    this.lockCheckBox.checked = this.locked;
	
	if(this.locked) this.lockIcon.style.visibility="visible";
	else this.lockIcon.style.visibility="hidden";
	
    Event.observe(this.lockCheckBox, "click", this.eventLockToggle);
    if (d.mode == DESIGNER_MODE_CONFIGURE) {
      this.lockContainer.style.display = "";
    } else {
      this.lockContainer.style.display = "none";
	  this.lockIcon.style.display="none";
    }
    
    this.managePaneBody = $("mp1_" + this.elId + "_body");
    
    this.setName(this.name);
    
    //this.iconContainer0 = $("mp0_" + this.id + "_ico_c");
    this.iconContainer1 = $("mp1_" + this.elId + "_ico_c");
    
    this.alertIcon = $("mp1_" + this.elId + "_ico_alert");
    this.alertContainers = [$("mp1_" + this.elId + "_a_error"), $("mp1_" + this.elId + "_a_warn"), $("mp1_" + this.elId + "_a_notice")];
    this.alertContainer = $("mp1_" + this.elId + "_alerts") ;
    this.initAlerts(); //lazy load any alerts added without managepane already loaded....
    this.initToolTips(this.managePane);
  },
  
  initToolTips: function Item_initToolTips(el) {
    var tt = el.getAttribute("tooltip");
    if(tt != null) new Tooltip(el, tt);
    var children = el.childNodes;
    for(var i=0; i < children.length; i++) {
      if(children[i].nodeType == 1) {
        this.initToolTips(children[i]);
      }
    }
  },
  
  setName: function Item_setName(name) {
    if((name!=null)&&(name.length > 15)) {
      this.name = name.substring(0,13) + "...";
    } else {
      this.name = name;
    }
    
    if(this.titleSpan != null) {
      this.titleSpan.innerHTML = this.name;
    }
  },
  
  addToDesigner: function Item_addToDesigner(doSelect) {
    this.el = this.buildElement();
    log("built el");
    var self = this;
    
    
    log("inited drag");
      
    if((this.options.l)||(this.options.t)||(this.options.w)||(this.options.h)) { //options contains positioning data
      this.setPosition();
    } else if(!this.startPosition()) {
      
      log("set Pos");
      this.setPosition();
      log("set Pos Done");
    }
    var self = this;
    
    this.el.onmousemove = function(ev) { self.rollover(); };
    this.el.onmouseout = function(ev) { self.leave(); };
    Event.observe(this.el, "mousedown", this.eventMouseDown);
    /*
    this.el.onclick = function(ev) {
      if (ev==null) {
        ev = window.event;
      }
      self.select(false, ev);
    };
    */
    this.positionType = this.getItemPositioning();
    this.showEL();
    if(doSelect) {
      this.select();
    }
    
    this.enableDragging();
  },
  
  enableDragging: function Item_enableDragging() {
    if(this.dragable == null && !this.locked) {
      var snapFunc = (this.isWilcomEMB || this.digitize || this.isSavedDigitized) ? this.constrainToCanvas.bind(this) : null;
      var self = this;
      if(useAlphaHack) {
        this.dragable = new Draggable(this.el.id, { 
          revert:false,
          starteffect: function Item_starteffect(element) { 
            //do nothing
          },
          endeffect: function Item_endeffect(element) { 
            //do nothing
            self.dragEnded();
          },
          change: function Item_change(dragable) {
            self.moving(dragable);
          },
          snap: snapFunc
        });
      } else {
        this.dragable = new Draggable(this.el.id,{
          revert:false,
          change: function Item_change(dragable) { self.moving(dragable); },
          endeffect: function Item_endeffect(element) {
            var t1 = new Effect.Opacity(element, {duration:0.2, from:0.7, to:1.0});
            self.dragEnded();
          },
          snap: snapFunc
        });
      }
    }
  },

  disableDragging: function Item_disableDragging() {
    if(this.dragable != null) {
      this.dragable.destroy();
      this.dragable = null;
    }
  
  },

  //move between products... scale and offsets in design scale
  moveToDesigner: function Item_moveToDesigner(cViewProcess, resizeScale, oldLeft, oldTop, offsetLeft, offsetTop) {
  
    if(this.el!=null) {
      this.cViewArea.canvas.removeChild(this.el);
      cViewProcess.configuredViewArea.canvas.appendChild(this.el);
    }
    var oldDScale = this.cViewProcess.productProcess.designScale;
    var scale = this.cViewProcess.productProcess.designScale / resizeScale / cViewProcess.productProcess.designScale;
  
    log("moveToDesigner scale=" + scale + " oScale=" + this.cViewProcess.productProcess.designScale + " nScale=" + cViewProcess.productProcess.designScale);
  
    if(this.managePane!=null) {
      this.managePane.parentNode.removeChild(this.managePane);
    
      cViewProcess.managePane.appendChild(this.managePane);
    }
    this.cViewProcess = cViewProcess;
    this.cViewArea = cViewProcess.configuredViewArea;
    this.cView = this.cViewArea.configuredView;
    
    log("moveToDesigner: before move: this.width=" + this.width + " this.height=" + this.height + " this.left=" + this.left + " this.top=" + this.top);
    
    this.width *= scale;
    this.height *= scale;
    
    if(this.zIndex == null) this.zIndex = this.cViewProcess.getNextZOrder();
    
  /*  this.left = this.left * oldDScale;
    log("left in design scale=" + this.left);
    this.left -= oldLeft;
    log("left after old left removed=" + this.left);
    this.left /= resizeScale;
    log("left after rescaled=" + this.left);
    this.left += offsetLeft;
    log("left after offset (" + offsetLeft + ") added=" + this.left);
    this.left /=  this.cViewProcess.productProcess.designScale;
    log("left after back in full scale=" + this.left);
    */
    
    this.left = ((((this.left * oldDScale) - oldLeft) / resizeScale) + offsetLeft) / this.cViewProcess.productProcess.designScale; //change to designer co-ords, remove old left, rescale, add new offset, put back to full scale 
    
    
    //this.left *= scale + (offsetLeft / this.cViewProcess.productProcess.designScale);
    this.top = ((((this.top * oldDScale) - oldTop) / resizeScale) + offsetTop) / this.cViewProcess.productProcess.designScale; //change to designer co-ords, remove old left, rescale, add new offset, put back to full scale
    //this.top *= scale + (offsetTop / this.cViewProcess.productProcess.designScale);
  
    this.setDirty(true, (resizeScale==1)); //dont queue updates (calling code will do this), use cached version if resizeScale == 1
    log("moveToDesigner: after move: this.width=" + this.width + " this.height=" + this.height + " this.left=" + this.left + " this.top=" + this.top);
  },
  
  startPosition: function Item_startPosition() {
    return false;
  },
   //skipCheck added because this is called when transferring designs between products and the view data is not setup yet
  setPosition: function Item_setPosition(skipCheck) {
    if(this.el==null) {
      return;
    }
    var dims = d.toCanvasDims({w:this.width, h:this.height, l:this.left, t:this.top},this.cViewProcess.productProcess );
    log(dims);
    this.setHeight(parseInt(dims.h, 10));
    this.setWidth(parseInt(dims.w, 10));
    if(!this.isMoving) {
      this.setTop(parseInt(dims.t, 10));
      this.setLeft(parseInt(dims.l, 10));
    }
    this.sizeChanged();
    if(skipCheck == null || skipCheck == false) {
      this.checkPosition();
    }
  },
  
  //used when zooming.. no need to check anything...
  quickSetPosition: function() {
    var dims = d.toCanvasDims({w:this.width, h:this.height, l:this.left, t:this.top},this.cViewProcess.productProcess );
    if(this.rotatedRef == null) {
      this.setReferenceRotation();
    }
    this.el.style.height = parseInt(dims.h, 10) + "px";      
    this.el.style.width = parseInt(dims.w, 10) + "px";
    this.el.style.top = parseInt(dims.t, 10) + "px";
    this.el.style.left = parseInt(dims.l, 10) + "px";
  },
  
  showPanel: function Item_showPanel() {
    if (this.itemVisible()) {
      this.managePane.style.display = ""
    } else {
      this.managePane.style.display="none";
    }
  },
  
  deleteClick: function Item_deleteClick(event) {
    Event.stop(event);
    if(d.mode == DESIGNER_MODE_AMEND) {
      if(this.cViewProcess.items.list.length == 1) {
        alert(ml("You cannot delete the last item using this decoration process as it will change the price"));
        return;
      }
    }
    
    var elementName = this.cViewProcess.productProcess.process.name;
    if(elementName){
      if(confirm(ml("Are you sure you wish to delete the selected %s?", (elementName+" "+this.itemTypeName) ))) {
        this.del();
      }
    }else{
      if(confirm(ml("Are you sure you wish to delete this?"))) {
        this.del();
      }
    }
  },
  
  del: function Item_del() {
    if(this.selected) {
      this.deSelect();
      this.cViewArea.selectItem(null);
    }
    //clear any existing alerts....
    for(var i=0; i < 3; i++) {
      var level = this.alerts[i];
      var keys = [];
      for(var k in level) {
        keys.push(k);
      }
      for(var j=0; j < keys.length; j++) {
        this.removeAlert(i, keys[j]);
      }
    }
    
    
    this.cViewProcess.deleteItem(this);
    if(this.managePane!=null) {
      Event.stopObserving(this.titleZUp, "click", this.zUpClickEvent);
      Event.stopObserving(this.titleZDown, "click", this.zDownClickEvent);
      Event.stopObserving(this.titleDel, "click", this.deleteClickEvent);
      this.managePane.parentNode.removeChild(this.managePane);
    }
    /*if(this.managePane0!=null) {
      Event.stopObserving(this.titleZUp0, "click", this.zUpClickEvent);
      Event.stopObserving(this.titleZDown0, "click", this.zDownClickEvent);
      Event.stopObserving(this.titleDel0, "click", this.deleteClickEvent);
      this.managePane0.parentNode.removeChild(this.managePane0);
    }*/
    if(this.el != null) {
      Event.stopObserving(this.el, "mousedown", this.eventMouseDown);
      this.cViewArea.canvas.removeChild(this.el);
    }
    this.cViewProcess.reSortZOrder();
    this.setDirty();
    //d.itemChanged(true);
  },
  
  getElementZIndex: function Item_getElementZIndex() {
    return (this.zIndex * 4) + (this.cViewProcess.productProcess.process.zIndex * 100);
  },
  
  zUpClick: function Item_zUpClick(event) {
    Event.stop(event);
    var pos = this.cViewProcess.items.objectIndex(this.id);
    log("zUpClick: pos=" + pos);
    if(pos >= this.cViewProcess.items.list.length-1) {
      return;
    }
    //if(pos == 0) {
    //  return;
    //}
    var swap = this.cViewProcess.items.list[pos+1];
    var oldpos = swap.zIndex;
    swap.zIndex = this.zIndex;
    swap.el.style.zIndex = swap.zIndex * 4;
    this.zIndex = oldpos;
    this.el.style.zIndex = this.zIndex * 4;
    var prev = this.managePane.previousSibling;
    log(prev);
    log(this.managePane.nextSibling);
    this.managePane.parentNode.removeChild(prev);
    if(this.managePane.nextSibling == null) {
      this.managePane.parentNode.appendChild(prev);
    } else {
      this.managePane.parentNode.insertBefore(prev , this.managePane.nextSibling);
    }
    this.cViewProcess.reSortZOrder();
    this.setDirty();
    //d.itemChanged(true);
  },
  
  zDownClick: function Item_zDownClick(event) {
    Event.stop(event);
    var pos = this.cViewProcess.items.objectIndex(this.id);
    log("zDownClick: pos=" + pos);
    //if(pos >= this.cViewProcess.items.list.length-1) {
    //  return;
    //}
    if(pos == 0) {
      return;
    }
    var swap = this.cViewProcess.items.list[pos-1];
    var oldpos = swap.zIndex;
    swap.zIndex = this.zIndex;
    swap.el.style.zIndex = swap.zIndex * 4;
    this.zIndex = oldpos;
    this.el.style.zIndex = this.zIndex * 4;
    
    if(this.managePane.nextSibling.nextSibling!=null) {
      var target = this.managePane.nextSibling.nextSibling;
      var parent = this.managePane.parentNode;
      parent.removeChild(this.managePane);
      parent.insertBefore(this.managePane, target);
    } else {
      this.managePane.parentNode.appendChild(this.managePane);
    }
    
    this.cViewProcess.reSortZOrder();
    this.setDirty();
    //d.itemChanged(true);
  },
  
  showEL: function Item_showEL() {
    this.el.style.display="";
  },
  
  setEnabled: function Item_setEnabled(enabled) {
    this.enabled = enabled;
    if(this.el != null) {
      if(enabled) {
        this.enableDragging();
        this.el.style.zIndex = this.zIndex * 4;
      } else {
        this.disableDragging();
        this.el.style.zIndex = 0;
      }
        
      if(useAlphaHack) {
        if(enabled) {
          this.el.style.display="";
        } else {
          this.el.style.display="none";
        }
      } else {
        if(enabled) {
          this.el.setOpacity(1);
        } else {
          this.el.setOpacity(0.3);
        }
      }
    }
  },
  
  setLocked: function Item_setLocked(locked) {
    this.locked = locked;
    if(this.el != null) {
      if(locked) {
        this.disableDragging();
      } else {
        this.enableDragging();
      }
    }
  },
  
  rollover: function Item_rollover() {
    if(this.enabled && !this.locked) {
      if(!this.selected) {
        this.setRolloverStyle();
        //this.managePane.className = "managepanehightlight";
      }
    }
  },
  
  setRolloverStyle: function Item_setRolloverStyle() {
    if((BrowserDetect.browser == "Explorer")||(BrowserDetect.browser == "Opera")) {
      this.el.style.borderStyle="dotted";
      this.el.style.borderWidth="1px";
      this.el.style.borderColor="black";
    } else {
      this.el.style.outlineStyle="dotted";
      this.el.style.outlineWidth="1px";
      this.el.style.outlineColor="invert";
    }
  },
  
  leave: function Item_leave() {
    if(this.enabled && !this.locked) {
      if(!this.selected) {
        this.setLeaveStyle();
        //this.managePane.className = "managepaneoff";   
      }
    }
  },
  
  setLeaveStyle: function Item_setLeaveStyle() {
    if((BrowserDetect.browser == "Explorer")||(BrowserDetect.browser == "Opera")) {
      this.el.style.borderStyle="none";
      this.el.style.borderWidth="0px";
    } else {
      this.el.style.outlineWidth="0px";
    }
    this.el.style.zIndex = this.getElementZIndex();
  },
  
  mouseDown: function Item_mouseDown(event) {
    this.select(false, event);
  },
  
  lockToggle: function Item_lockToggle(event) {
    log("locked: " + this.lockCheckBox.checked);
    if (this.lockCheckBox.checked) {
      this.setLocked(true);
	  this.lockIcon.style.visibility="visible";
    } else {
      this.setLocked(false);
	  this.lockIcon.style.visibility="hidden";
    }
  },
  
  select: function Item_select(dontEnterCustomisePane, event) {
    log("select " + this.id);
    if(!this.enabled || (this.locked && d.mode!=DESIGNER_MODE_CONFIGURE)) {
      log(event);
      if(this.locked) {
        log("item is locked..not passing through....");
        return false;
      }
      if(event == null) {
        log("item is disabled..event is null..not passing through....");
        return false;
      }
      var pointer = this.cView.getLayoutMousePosition(event);
      log("item is disabled..passing through....");
      this.cView.proxyMouseDown(pointer[0],pointer[1], event);
      return false;
    }
    if(dontEnterCustomisePane != true) {
      log("selecting customize tab", true);
      d.selectTab('m','customize'); 
      //d.expandManage();
      //this.autoRepositionHandles();
    }
    
    if(!this.selected) {
      this.cViewArea.selectItem(this);
      this.selected = true;
      this.setSelectStyle();
      //this.el.style.zIndex=1000;
      if(this.managePaneBody!=null) {
        this.managePaneBody.style.display = "";
        this.titleBar.style.cursor="";
      }
      /*if(this.managePane0!=null) {
        this.managePane0.className = "managepaneselected";
      }*/
      if(this.managePane!=null) {
        this.managePane.className = "managepaneselected";
        if (!this.itemReady()) this.disablePane();
      }
      this.addHandles();
    } else {
      log("Item.select: already selected:" + this.id); 
      this.autoRepositionHandles();
    }
    
    
  },
  
  setSelectStyle: function Item_setSelectStyle() {
    if((BrowserDetect.browser == "Explorer")||(BrowserDetect.browser == "Opera")) {
      this.el.style.borderStyle="solid";
      this.el.style.borderWidth="1px";
      this.el.style.borderColor="black";
    } else {
      this.el.style.outlineStyle="solid";
      this.el.style.outlineWidth="1px";
      this.el.style.outlineColor="invert";
    }
    this.el.style.zIndex = 1000;
  },
  
  deSelect: function Item_deSelect() {
    if (!this.itemReady()) {
      log("deselected !itemReady() item");
      this.selected = false;
      return;
    }
    
    log("deselect " + this.id);
    this.setLeaveStyle();
    //this.el.style.zIndex=this.zIndex * 4;
    this.selected = false;
    this.removeHandles();
    if(this.managePaneBody!=null) {
      this.titleBar.style.cursor="pointer";
      this.managePaneBody.style.display = "none";
    }
    /*if(this.managePane0!=null) {
      this.managePane0.className = "managepaneoff2";
    }*/
    if(this.managePane!=null) {
      this.managePane.className = "managepaneoff2";
    }
  },
  
  getDims: function Item_getDims() {
    return {t: parseFloat(this.el.style.top),l:parseFloat(this.el.style.left), h:parseFloat(this.el.style.height), w:parseFloat(this.el.style.width)};
  },
  
  //get the dims for the canvas using the final dims * scale (we use design scale)
  getCanvasDims: function Item_getCanvasDims() {
    var scale = this.cViewProcess.productProcess.designScale;
    return {t: parseInt(this.top * scale, 10), l:parseInt(this.left * scale, 10), h:parseInt(this.height * scale, 10), w:parseInt(this.width * scale, 10)};
  },
  
  fromCanvasDim: function Item_fromCanvasDim(dim) {
    var scale = (d.currentCanvasType==0) ? this.cViewProcess.productProcess.layoutScale : this.cViewProcess.productProcess.designScale;
    return dim / scale;
  },
  
  toCanvasDim: function Item_toCanvasDim(dim) {
    var scale = (d.currentCanvasType==0) ? this.cViewProcess.productProcess.layoutScale : this.cViewProcess.productProcess.designScale;
    return dim * scale;
  },
  
  toCanvasDims: function Item_toCanvasDims() {
    return d.toCanvasDims({w:this.width, h:this.height, l:this.left, t:this.top},this.cViewProcess.productProcess );
  },
  
  moving: function Item_moving(dragable) {
    if(!this.selected) {
      this.select();
    }
    if(!this.isMoving) {
      this.moveStarted();
      this.isMoving = true;
    }
  },
  
  moveStarted: function Item_moveStarted() {
    this.removeHandles();
  },
  
  moveFinished: function Item_moveFinished() {
    log("moveFinished " + this.id);
    
    this.isMoving = false;
    var dims = d.fromCanvasDims(this.getDims(), this.cViewProcess.productProcess);
    this.width = dims.w;
    this.height = dims.h;
    this.top = dims.t;
    this.left = dims.l;
    this.addHandles();
    this.checkPosition();
  },
  
  constrainToCanvas: function Item_constrainToCanvas(x,y) {
    
    log("x=" + x + ", y=" + y);
    
    var dims = this.getDims();
    var cSize = this.cViewArea.canvasSize();
    
    if(x + dims.w > cSize.w) {
      x = cSize.w - dims.w;
    }
    if(x < 0) {
      x = 0;
    }
    if(y + dims.h > cSize.h) {
      y = cSize.h - dims.h;
    }
    if(y < 0) {
      y = 0;
    }
    return [x,y];
  },
  
  //is the item inside (0), outside (1) or cropped (2)
  getItemPositioning: function Item_getItemPositioning() {
    var idims = this.getDims();
    var cdims = this.cViewArea.canvasSize();
    
    var somethingOutside = false;
    var somethingInside = false;
    var allInside = true;
    if(idims.t > cdims.h) {//top is below
      somethingOutside = true;
      allInside = false;
    } else if(idims.t+idims.h < 0) { //bottom is above top
      somethingOutside = true;
      allInside = false;
    } else {
      if((idims.t < 0) || (idims.t+idims.h > cdims.h) ) { //not vertically all inside...
        allInside = false;
      }
      if(idims.l > cdims.w) { //left is to right of canvas
        somethingOutside = true;
        allInside = false;
      } else if(idims.l+idims.w < 0){ //right is to left of canvas
        somethingOutside = true;
        allInside = false;
      } else {
        somethingInside = true;
        if((idims.l < 0) || (idims.l+idims.w > cdims.w) ) { //not horizontally all inside...
          allInside = false;
        }
      }
    }
    if(allInside) {
      return 0;
    } else if(!somethingInside) {
      return 1;
    }
    return 2;
  },
  
  dragEnded: function Item_dragEnded() {
    //test if the div is inside the canvas.. if not delete it
    
    var newPositionType = this.getItemPositioning();
    
    log("dragEnded, newPositionType=" + newPositionType);
    if(newPositionType == 1) {
      log("del me!");
      this.del();
    } else if(this.isMoving) {
      //the dropable didnt pick this up.. fix it...
      log("Fixing drop..:" + this.isMoving);
      this.moveFinished();
    }
    
    //we want to up the render version if the item is cropped or postion type has changed
    this.setDirty(false, ((this.positionType == newPositionType) && newPositionType != 2));
    
    this.positionType = newPositionType; 
    //d.itemChanged(true);
  },
  
  //callback fired whenever the position/size has changed..
  checkPosition: function Item_checkPosition() {
    //do nothing...
  },
  
  buildSizer: function Item_buildSizer(cursor, position) {
    if((!this.allowHandleResizing)||(!this.allowResize)) {
      return this.buildReadOnlySizer(cursor, position);
    }
    if(this.sizers == null) {
      //console.debug("new sizer array");
      this.sizers = new Hash();
    }
    var sizer = d.sizer.cloneNode(true);
    sizer.id = d.getNextId();
    sizer.style.cursor = cursor;
    sizer.style.zIndex = 1010;
    sizer.positioning_mode = position;
    document.body.appendChild(sizer);
    this.sizers[position] = sizer;
    Event.observe(sizer, "mousedown", this.eventResizeStart);
    return sizer;
  },
  
  buildReadOnlySizer: function Item_buildReadOnlySizer(cursor, position) {
    if(this.sizers == null) {
      //console.debug("new sizer array");
      this.sizers = new Hash();
    }
    var sizer = d.roSizers[position].cloneNode(true);
    sizer.id = d.getNextId();
    sizer.style.zIndex = 1010;
    sizer.positioning_mode = position;
    document.body.appendChild(sizer);
    this.sizers[position] = sizer;
    return sizer;
  },
  
  resizeStart: function Item_resizeStart(event) {
    if(this.handleResizeStart(event)) {
      
    } else {
      this.currentSizer = Event.element(event);
      log("resizeStart for " + this.currentSizer.positioning_mode);
      
      Event.observe(document, "mouseup", this.eventResizeMouseUp);
      Event.observe(document, "mousemove", this.eventResizeMouseMove);
      Event.stop(event);
    }
    return false;
  },
  
  handleResizeStart: function Item_handleResizeStart(event) {
    return false;
  },
  
  resizeMove: function Item_resizeMove(event) {
    //log("resizeMove");
    var pointer = [Event.pointerX(event), Event.pointerY(event)];
    if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) {
      return false;
    }
    this._lastPointer = pointer;
    
    
    var pl = pointer[0]-PPSizerHalf;
    var pt = pointer[1]-PPSizerHalf;
    
    
    
    var pm = this.currentSizer.positioning_mode;
    
    var dims = this.cViewArea.abs(this.getDims());
    var t = dims.t;
    var l = dims.l;
    var h = dims.h;
    var w = dims.w;
    
    var ot = t;
    var ol = l;
    var oh = h;
    var ow = w;
    
    if(pm == "BR") {
      h = pointer[1] - t;
      w = pointer[0] - l;
      if(!this.setHeight(h)) {
        h = this.getDims().h;
        pt = t + h - PPSizerHalf;
      }
      if(!this.setWidth(w)) {
        w = this.getDims().w;
        pl = l + w - PPSizerHalf;
      }
      this.repositionHandles("BR",t,l,h,w);
    } else if(pm == "BL") {
      h = pointer[1] - t;
      w = w + (l - pointer[0]);
      l = pointer[0];
      if(!this.setHeight(h)) {
        h = this.getDims().h;
        pt = t + h - PPSizerHalf;
      }
      if(!this.setWidth(w)) {
        w = this.getDims().w;
        l = (ol + ow) - w;
        pl = l - PPSizerHalf;
        this.el.style.left = (l - this.cViewArea.canvasX) + "px";
      } else {
        this.el.style.left = (l - this.cViewArea.canvasX) + "px";
      }
      this.repositionHandles("BL",t,l,h,w);
    }  else if(pm == "TL") {
      h = h + (t - pointer[1]);
      w = w + (l - pointer[0]);
      t = pointer[1];
      l = pointer[0];
      if(!this.setHeight(h)) {
        h = this.getDims().h;
        t = (ot + oh) - h;
        pt = t - PPSizerHalf;
        this.el.style.top = (t - this.cViewArea.canvasY) + "px";
      } else {
        this.el.style.top = (t - this.cViewArea.canvasY) + "px";
      }
      if(!this.setWidth(w)) {
        w = this.getDims().w;
        l = (ol + ow) - w;
        pl = l - PPSizerHalf;
        this.el.style.left = (l - this.cViewArea.canvasX) + "px";
      } else {
        this.el.style.left = (l - this.cViewArea.canvasX) + "px";
      }
      
      this.repositionHandles("TL",t,l,h,w);
    } else if(pm == "TR") {
      h = h + (t - pointer[1]);
      w = pointer[0] - l;
      t = pointer[1];
      if(!this.setHeight(h)) {
        h = this.getDims().h;
        t = (ot + oh) - h;
        pt = t - PPSizerHalf;
        this.el.style.top = (t - this.cViewArea.canvasY) + "px";
      } else {
        this.el.style.top = (t - this.cViewArea.canvasY) + "px";
      }
      if(!this.setWidth(w)) {
        w = this.getDims().w;
        pl = l + w - PPSizerHalf;
      }
      this.repositionHandles("TR",t,l,h,w);
    }
    
    this.currentSizer.style.left = pl + "px";
    this.currentSizer.style.top = pt + "px";
    
    var dims = d.fromCanvasDims(this.getDims(),this.cViewProcess.productProcess);
    this.width = dims.w;
    this.height = dims.h;
    this.top = dims.t;
    this.left = dims.l;
    this.sizeChanged();
    return false;
  },
  
  resizeFinished:  function(event) {
    log("resizeFinished");
    this.releaseResizing();
    
    var dims = d.fromCanvasDims(this.getDims(),this.cViewProcess.productProcess);
    this.width = dims.w;
    this.height = dims.h;
    this.top = dims.t;
    this.left = dims.l;
    this.sizeChanged();
    this.checkPosition();
    //d.itemChanged(true);
    this.setDirty();
    d.selectTab('m','customize'); 
    //d.expandManage();
  },
  
  releaseResizing: function Item_releaseResizing() {
    this._lastPointer = null;
    this.currentSizer = null;
    Event.stopObserving(document, "mouseup", this.eventResizeMouseUp);
    Event.stopObserving(document, "mousemove", this.eventResizeMouseMove);
  },
  
  addHandles: function Item_addHandles() {
    if(this.hasHandles) {
      this.removeHandles();
    }
    log("addHandles", true);
    var dims = this.toCanvasDims();
    dims = this.cViewArea.abs(dims);
    //var dims = this.cViewArea.abs(this.getDims());
    var t = dims.t;
    var l = dims.l;
    var h = dims.h;
    var w = dims.w;

    //console.debug(dims);
    
    var sizer = this.buildSizer("nw-resize","BR");
    
    
    this.positionHandle(sizer,"BR",t,l,h,w);
    sizer.style.display="";
    
    
    sizer = this.buildSizer("ne-resize","BL");
    this.positionHandle(sizer,"BL",t,l,h,w);
    sizer.style.display="";
    
    sizer = this.buildSizer("nw-resize","TL");
    this.positionHandle(sizer,"TL",t,l,h,w);
    sizer.style.display="";
    
    sizer = this.buildSizer("ne-resize","TR");
    this.positionHandle(sizer,"TR",t,l,h,w);
    sizer.style.display="";
    
    this.hasHandles = true;
    
  },
  
  removeHandles: function Item_removeHandles() {
    if(this.sizers!=null) {
      var self = this;
      this.sizers.each(function(pair) {
        if(pair.value!=null) {
          Event.stopObserving(pair.value, "mousedown", self.eventResizeStart);
          document.body.removeChild(pair.value);
        }
      });
      this.sizers = null;
    }
    this.hasHandles = false;
  },
  
  positionHandle: function Item_positionHandle(sizer, pos, t, l, h, w) {
    try {
      if(pos=="BR") {
        sizer.style.left = (l + w - PPSizerHalf) + "px";
        sizer.style.top = (t + h - PPSizerHalf) + "px";
      } else if(pos=="TL") {
        sizer.style.left = (l - PPSizerHalf) + "px";
        sizer.style.top = (t - PPSizerHalf) + "px";
      } else if(pos=="TR") {
        sizer.style.left = (l + w - PPSizerHalf) + "px";
        sizer.style.top = (t- PPSizerHalf) + "px";
      } else if(pos=="BL") {
        sizer.style.left = (l - PPSizerHalf) + "px";
        sizer.style.top = (t + h - PPSizerHalf) + "px";
      } else {
        log("Unknown position:" + pos);
      }
    } catch(e) {}
  },
         
  repositionHandles: function Item_repositionHandles(exclude, t,l,h,w) {
    var self = this;
    if(this.sizers==null) {
      this.addHandles();
    }
    this.sizers.each(function(pair) {
      if(pair.key != exclude) {
        //console.debug(key);
        self.positionHandle(pair.value, pair.key, t,l,h,w);
      }
    });
  },
  
  autoRepositionHandles: function Item_autoRepositionHandles() {
    //var dims = d.toCanvasDims({w:this.width, h:this.height, l:this.left, t:this.top},this.cViewProcess.productProcess );
    //dims = this.cViewArea.abs(dims);
    var dims = this.cViewArea.abs(this.getDims());
    this.repositionHandles("",dims.t, dims.l, dims.h, dims.w);
  },
  
  sizeChanged: function Item_sizeChanged() {
    this.updateTitleSize();
  },
  
  minDims: function Item_minDims(dims) {
    return dims;
  },
  
  //check if we can rescale this item using desiredScale to work with process...
  checkScale: function Item_checkScale(desiredScale, process) {
    return desiredScale; //default behaviour
  },
  
  serializeToOptions: function Item_serializeToOptions(o) {
    if(o == null) o = {};
    o.id =this.id;
    o.p =this.cViewProcess.id;
    o.rv =this.renderVersion;
    o.lk =this.locked;
    o.w =this.width;
    o.h =this.height;
    o.l =this.left;
    o.t =this.top;
    o.z =this.zIndex;
    o.it =this.asset.getItemType();
    var aid = this.asset.id;
    if(aid!=null) {
      o.aid =aid;
    }
    
    if(this.isWilcomEMB) {
      o.emb=1;
      o.stc=this.stitchCount;
    }
    return o;
  },
  
  serialize: function Item_serialize(queryComponents, prefix) {
    if(prefix==null) {
      prefix = "t[" + this.id + "]";
    }
    var o = this.serializeToOptions();
    
    if(queryComponents==null) {
      queryComponents = new Array();
    }
    
    serializeObject(queryComponents, prefix, o);
    
    return queryComponents.join('&');
  },
  
  
  
  serializeOLD: function Item_serialize(queryComponents, prefix) {
    if(prefix==null) {
      prefix = "t[" + this.id + "]";
    }
    if(queryComponents==null) {
      queryComponents = new Array();
    }
    queryComponents.push(encodeURIComponent(prefix + "[id]") + "=" + encodeURIComponent(this.id));
    queryComponents.push(encodeURIComponent(prefix + "[p]") + "=" + encodeURIComponent(this.cViewProcess.id));
    queryComponents.push(encodeURIComponent(prefix + "[rv]") + "=" + encodeURIComponent(this.renderVersion));
    queryComponents.push(encodeURIComponent(prefix + "[lk]") + "=" + encodeURIComponent(this.locked));
    queryComponents.push(encodeURIComponent(prefix + "[w]") + "=" + encodeURIComponent(this.width));
    queryComponents.push(encodeURIComponent(prefix + "[h]") + "=" + encodeURIComponent(this.height));
    queryComponents.push(encodeURIComponent(prefix + "[l]") + "=" + encodeURIComponent(this.left));
    queryComponents.push(encodeURIComponent(prefix + "[t]") + "=" + encodeURIComponent(this.top));
    queryComponents.push(encodeURIComponent(prefix + "[z]") + "=" + encodeURIComponent(this.zIndex));
    queryComponents.push(encodeURIComponent(prefix + "[it]") + "=" + encodeURIComponent(this.asset.getItemType()));
    var aid = this.asset.id;
    if(aid!=null) {
      queryComponents.push(encodeURIComponent(prefix + "[aid]") + "=" + encodeURIComponent(aid));
    }
    
    if(this.isWilcomEMB) {
      queryComponents.push(encodeURIComponent(prefix + "[emb]") + "=" + encodeURIComponent(1));
      queryComponents.push(encodeURIComponent(prefix + "[stc]") + "=" + encodeURIComponent(this.stitchCount));
    }
    return queryComponents.join('&');
  },
  
  //x,y come in at layout scale...
  hitTest: function Item_hitTest(x,y) {
    var scale = this.cViewProcess.productProcess.layoutScale;
    x = x / scale;
    y = y / scale;
     
    if((x > this.left)&&(x < this.left + this.width)) {
      if((y > this.top)&&(y < this.top + this.height)) {
        return true ;
      }
    }
    log("Item.hitTest miss: scale=" + scale + " x.y=" + x + "." + y);
    log(this);
    if(x < this.left) {
      log("To Left");
    } 
    if (x > this.left + this.width) {
      log("To Right");
    } 
    if(y < this.top) {
      log("Above");
    } 
    if (y > this.top + this.height) {
      log("Below");
    }
    return false;
  },
  
  setAsset: function Item_setAsset(asset) {
    
  },
  
  checkQuality: function Item_checkQuality() {
    return false;
  },
  
  setQualityWarning: function Item_setQualityWarning(allOk) {
    
    if(allOk) {
      if(!this.qualityOK) {
        this.removeAlert(1,"quality_warning");
      }
  //    if(this.qualityIcon1!=null) {
  //      this.iconContainer1.removeChild(this.qualityIcon1);
  //      this.qualityIcon1 = null;
  //    }
    } else if(this.qualityOK) {
      this.addAlert(1,"quality_warning", "alert_quality_warning", ml("Poor Quality"), ml("This image has been resized to the point that it may appear blurred."), true);
    }
    this.qualityOK = allOk;
  },
  
  //dontUpdateRenderVersion: the image was only moved (not resized etc) so the cached version on the server is ok
  setDirty: function Item_setDirty(dontQueueUpdate, dontUpdateRenderVersion) {
    if(dontUpdateRenderVersion != true) {
      this.renderVersion++;
      this.reRender = true;
    } else {
      log("dontUpdateRenderVersion");
    }
    var queueUpdate = !(dontQueueUpdate == true);
    this.cViewArea.setChildReRender(queueUpdate);
  },
  
  clearReRender: function Item_clearReRender() {
    this.reRender = false;
  },
  
  //start updating the element with s status showing... track versions to multiple queued updates keep status showing
  startUpdating: function Item_startUpdating() {
    if(this.el == null) {
      return {v: null} ;
    }
    if(this.updateKey == null) {
      this.updateKey = asyncStart(this.el);
    }
    this.updateVersion = this.renderVersion;
    return {k: this.updateKey, v: this.updateVersion};
  },
  
  //if the updateInfo (return value of startUpdating) is latest version then finish the async
  finishUpdating: function Item_finishUpdating(updateInfo) {
    if(this.updateKey != null) {
      if(this.updateVersion == updateInfo.v) {
        asyncFinish(this.updateKey);
        this.updateKey = null;
        this.updateVersion = null;
      }
    }
  },
  
  disablePane: function Item_disablePane() {
    if(this.managePane != null && this.paneKey == null) {
      this.paneKey = asyncStart(this.managePane);
    }
  },
  
  enablePane: function Item_enablePane() {
    if(this.paneKey != null) {
      asyncFinish(this.paneKey);
      this.paneKey = null;
    }
  },
  
  //add an alert
  //level: 0=error, 1=warning, 2 = notice
  addAlert: function Item_addAlert(level, alertKey, bodyClass, alertTitle, alertMessage, warnAddToCart) {
    var alertData = {level:level, bodyClass:bodyClass, alertTitle:alertTitle, alertKey:alertKey, alertMessage:alertMessage, warnAddToCart:warnAddToCart};
    var levelData = this.alerts[level];
    levelData[alertKey] = alertData;
    if(this.alertIcon) {
      if((this.alertLevel == null)||(this.alertLevel > level)) {
        //we need to update the icon..
        this.alertIcon.className = alertLevelHeaderClasses[level];
        this.alertLevel = level;
      }
    }
    if(this.alertContainers != null) {
      //get the ol for the level
      this.addAlertToContainer(level, alertData);
    }
    this.cView.configuredProduct.setAlertIcons();
  },
  
  addAlertToContainer: function Item_addAlertToContainer(level, alertData) {
    var ol = this.alertContainers[level];
    
    //make the li to contain the alert
    
    var li = document.createElement("LI");
    li.className = alertData.bodyClass ;
    li.innerHTML = alertData.alertMessage ;
    //append li to ol of level
    ol.appendChild(li);
    ol.style.display="";
    this.alertContainer.style.display="";
    //add alert data to this.alerts
    alertData.li = li;
  },
  
  //lazy loading support
  initAlerts: function Item_initAlerts() {
    for(var level =0; level < 3; level ++) { //for each level
      for(var alertKey in this.alerts[level]) { //for each alert in the level
        var alertData = this.alerts[level][alertKey]; //get the alert data...
        if((this.alertLevel == null)||(this.alertLevel > level)) {
          //we need to update the icon..
          if(this.alertIcon) this.alertIcon.className = alertLevelHeaderClasses[level];
          this.alertLevel = level;
        }
        if(alertData.li == null) { //the alert is not displayed yet..
          this.addAlertToContainer(level, alertData);
        }
      }
    }
  },
  
  removeAlert: function Item_removeAlert(level, alertKey) {
    var levelData = this.alerts[level];
    var alertData = levelData[alertKey];
    //remove the li
    if(alertData.li != null) {
      alertData.li.parentNode.removeChild(alertData.li);
    }
    delete levelData[alertKey]; //remove the alert data from the level data
    
    //now go through each level to set correct data/displays
    var foundLevel = false ;
    for(var i=0; i < 3; i++) {
      if(hashSize(this.alerts[i]) == 0) {
        if(this.alertContainers) this.alertContainers[i].style.display="none";
      } else {
        if(!foundLevel) {
          if(this.alertLevel != i) {
            if(this.alertIcon) this.alertIcon.className = alertLevelHeaderClasses[i];
            this.alertLevel = i;
          }
          foundLevel = true;
        }
      }
    }
    if(!foundLevel) {
      if(this.alertIcon) this.alertIcon.className = "alert_icon_none";
      this.alertLevel = null;
      if(this.alertContainer) this.alertContainer.style.display="none";
    }
    this.cView.configuredProduct.setAlertIcons();
  }, 
  
  updateAlertMessage: function Item_updateAlertMessage(level, alertKey, title, message) {
    var levelData = this.alerts[level];
    var alertData = levelData[alertKey];
    alertData.title = title;
    alertData.alertMessage = message;
    if(alertData.li != null) {
      alertData.li.innerHTML = message;
    }
  },
  
  getAlerts: function Item_getAlerts(types, allAlerts) {
    for(var i=0; i < types.length; i++) {
      var level = types[i];
      log("checking alerts of type " + level);
      var alerts = allAlerts[level];
      var levelData = this.alerts[types[i]];
      for(k in levelData) {
        if(levelData[k].warnAddToCart) {
          log("Adding alert " + k);
          if(alerts[k] == null) {
            alerts[k] = {items: []};
          }
          var src = this.getSrc();
          var dims = this.fitToSize(50);
          alerts[k].items.push({id:this.id, errorThumb: src, width: dims.w, height: dims.h});
        }
      }
    }
  },
  
  fitToSize: function Item_fitToSize(side) {
    var aspectRatio = parseFloat(this.width) / parseFloat(this.height);
    if(this.width > this.height) {
      return {w: side, h: parseFloat(side) / aspectRatio};
    } else {
      return {h: side, w: parseFloat(side) * aspectRatio};
    }
  },
  
  allowFeature: function(feature) {
    return true;
  },
  
  updateTitleSize: function Item_updateTitleSize() {
    if (this.titleSize != null && this.width != null && this.height != null) {
      var w = 0;
      var h = 0;
      if(this.rotated) {
        var dims = this.getRealDims();
        w = dims.w / this.cViewProcess.productProcess.perfectDPI;
        h = dims.h / this.cViewProcess.productProcess.perfectDPI;
      } else {
        w = this.width / this.cViewProcess.productProcess.perfectDPI;
        h = this.height / this.cViewProcess.productProcess.perfectDPI;
      }
      this.titleSize.innerHTML = d.convertLengthFromInches(w).toFixed(2) + d.getLengthUnit() + " x " + d.convertLengthFromInches(h).toFixed(2) + d.getLengthUnit();
    }
  },
  
  setFeature: function(feature, enabled) {
    if(this.features == null) this.features = {};
    this.features[feature] = enabled;
    var el = $("mp1_"+this.elId+"_fc_" + feature);
    if(el != null) {
      if(enabled) {
        el.show();
      } else {
        el.hide();
      }
    }
  },
  
  initFeature: function(feature) {
    if((this.features == null)||(this.features[feature] == null)) return; //nothing to do....
    this.setFeature(feature, this.features[feature]);
  },
  
  itemReady: function Item_itemReady() {
    if (!this.ready) {
      if (this.top != null) {
        this.ready = true;
      }
    }
    return this.ready;
  },
  
  itemVisible: function Item_itemVisible() {
    if (d.mode != DESIGNER_MODE_CONFIGURE && this.locked) {
      return false;
    } else {
      return true;
    }
  },
  
  copyTo: function Item_copyTo(destArea) {
    var allowedProcesses = destArea.getAllowedProcesses();
    var passed = 0;
    if(allowedProcesses[this.cViewProcess.id]) {
      var process = destArea.processes[this.cViewProcess.id];
      var initData = this.serializeToOptions();
      //centered (remove t/l)
      initData.l = null;
      initData.t = null; 
      initData.z = null; //need new zindex
      var newId = destArea.configuredProduct.getNextItemId();
      var asset = this.asset;
      eval("var newItem = new " + this.CLASSDEF.name + "(newId, process, asset, initData);");
      destArea.insertNewItem(newItem);
      passed += 1;
      newItem.select();
      d.itemChanged(true);
    }
    return [passed, 1];
  },
  
  copy: function() {
    var initData = this.serializeToOptions();
    var newId = this.cViewArea.configuredProduct.getNextItemId();
    var asset = this.asset;
    eval("var newItem = new " + this.CLASSDEF.name + "(newId, this.cViewProcess, asset, initData);");
    this.cViewArea.insertNewItem(newItem);
    return newItem;
  }

});
