var ConfiguredProduct = Class.create({
  CLASSDEF: {
      name: 'ConfiguredProduct'
  },
  
  initialize: function CP_initialize(id, options) {
    this.id = id;
    if(this.cartIndex == null) this.cartIndex = d.cart.products.length;
    this.options = options;
    this.cp_type = options.cp_type;
    if(options.q) {
      this.qty = parseInt(options.q, 10);
    } else {
      this.qty = 1;
    }
    if(this.options.lv) {
      this.layout_version = parseInt(this.options.lv, 10);
    } else {
      this.layout_version = 0;
    }
    this.discount = parseFloat(options.dis);
    
    this.views = {};
    this.product = d.productsById[options.p];
    this.nextItemId = 1; //this id is unique per configured product.... allows us to cache stuff on the server....
    this.brandId = options.b;
    this.markupMode = d.brandMarkups[this.brandId].mode;
    this.markupAmount = d.brandMarkups[this.brandId].amount;
    if ((!this.markupMode && this.markupMode != 0) || (!this.markupAmount && this.markupAmount != 0)){
      log("No markup details for CP: "+this.id+" with brand of "+this.brandId+": "+d.brandMarkups[this.brandId]);
    }else{
      log("set markup details for CP: "+this.id+" with brand of "+this.brandId+": "+this.markupMode+", "+this.markupAmount);
    }
    
    this.renderVersion = (options.lv == null) ? 0 : options.lv;
    this.reRender = false; //track changes on this object that need rerendering (make all child objects rerender)
    this.reRenderChild = false; //track if children have made changes requiring rerendering
    this.price = null;
    this.addedToCart = options.added;
      
    if(this.cp_type == CP_DIGITIZATION) {
      this.asset_id = options.asset_id;
      this.price = options.price;
//      this.primaryItemId = options.cpa;
    } else {
    
      this.usingTeamnames = (options.utn==true);
      if(this.usingTeamnames) {
        if(options.tn != null && options.tn.length > 0) {
          this.getTeamNames().load(options.tn);
          this.usingTeamnames = true;
        } else {
          this.usingTeamnames = false;
        }
      }
      
      
      
      this.initFields(); //init the field objects
  
      this.usesDecorationLibrary = null; // start as null, as we don't know yet, could be true or false    
  
      
      
      
      //load fields
      for(var i=0; i < options.f.length; i++) {
        var fieldData = options.f[i];
        var cField = this.cFields[fieldData.id];
        if(cField != null) {
          for(var j=0; j < fieldData.opts.length; j++) {
            var optData = fieldData.opts[j];
            var cOpt = cField.addSelectedOption(optData.id, optData.qty);
            if(cOpt != null) {
              for(var k=0; k < optData.sub.length; k++) {
                var subData = optData.sub[k];
                cOpt.addSelectedOption(subData.id, subData.qty);
              }
            }
          }
        } else {
          log("Dropping Configured Field " + fieldData.id);
        }
        
      }
      
      this.initFieldDefaults();
      
      var views = options.v;
      
      this.customProductId = options.cp;
      if(this.customProductId != null) {
        this.customProduct = d.customProducts[this.customProductId];
        if(views.length == 0) { //no views defined in configured product... use the views defined in the custom product....
          log("Loading views from custom product definition");
          views = this.customProduct.viewOptions;
        }
      }
      for(var i=0; i < views.length;i++) {
        var view = views[i];
        var productView = this.product.views.byId[view.id];
        if(productView==null) {
          log("Error loading custom product view: Product does not have view " + view.id);
        } else {
          log("init view:" + productView.id);
          this.views[productView.id] = new ConfiguredView(this, productView, view);
        }
      }
      if(options.def_proc == null && options.def_proc != -1) {
        if((this.customProduct != null)&&(this.customProduct.defaultProcessId != null)) {
          this.defaultProcessId = this.customProduct.defaultProcessId;
        } else if(d.defaultProcess == null) {
          this.defaultProcessId = this.product.getFirstProcessId(); 
        } else {
          this.defaultProcessId = d.defaultProcess.id;
        }
      } else {
        this.defaultProcessId = options.def_proc;
      }
      
      
      
      this.selectedColorId = options.color;
      if((this.selectedColorId == null) && (this.usingCustomProduct())) {
        this.selectedColorId = this.customProduct.defaultColor;
      }
    }
  },
  
  toString: function() {
    return this.product.name;
  },
  
  initFields: function CP_initFields() {
    this.cFields = {};
    //load from configured product options first
    var fieldOpts = this.options.f;
    if(fieldOpts==null) fieldOpts = []; //this shouldnt happen but DNC-2317 says it must....
    for(var i=0; i < fieldOpts.length; i++) {
      var fieldOpt = fieldOpts[i];
      var field = this.product.type.fields.byId[fieldOpt.id];
      if(field != null) {
        var pField = this.product.fields.byId[field.id];
        if(pField!=null) { //product may not support field....
          var cField = new ConfiguredField(field.id, this, fieldOpt);
          this.cFields[cField.id] = cField;
        }
      }
    }
    //now laod all fields not in the options...
    for(var i=0; i < this.product.type.fields.list.length; i++) {
      var field = this.product.type.fields.list[i];
      if(this.cFields[field.id] == null) {
        var pField = this.product.fields.byId[field.id];
        if(pField!=null) { //product may not support field....
          var cField = new ConfiguredField(field.id, this, {uDef: true});
          this.cFields[cField.id] = cField;
        }
      }
    }
  },
  
  initFieldDefaults: function CP_initFieldDefaults() {
    for(var k in this.cFields) {
      this.cFields[k].initToDefault();
    }
  },
  
  getTeamNames: function() {
    if(this.teamNames == null) {
      this.teamNames = new TeamNames(this);
    }
    return this.teamNames;
  },
  
  //build the html displaying the views 
  updateViewListHtml: function CP_updateViewListHtml() {
    var colorId =  this.getSelectedColorId();
    /*var colorId = 0;
    if(color!=null) {
      colorId = color.productChosenOptionId;
    }*/
    
    var customProduct = (this.usingCustomProduct() && !this.isCustomised()) ? this.customProduct : null;
    if(customProduct != null) {
      log("Using Custom Product to updateViewListHtml");
    } else {
      log("NOT Using Custom Product to updateViewListHtml: this.usingCustomProduct()=" + this.usingCustomProduct() + " this.isCustomised()=" + this.isCustomised());
    }
    var html = '';
    for(var i=0;i < this.product.views.list.size(); i++) {
      var pView = this.product.views.list[i];
      html += pView.buildSelectorHtml(colorId, this.getView(pView.id, false), customProduct);
    }
    $("product_views").innerHTML = html;
  },
  
  getView: function CP_getView(viewId, createIfNotFound) {
    var view = this.views[viewId];
    if((view == null) && (createIfNotFound==true)) {
      var productView = this.product.views.byId[viewId];
      if(productView==null) {
        log("No defined view " + viewId);
      }
      view = new ConfiguredView(this,productView, {});
      this.views[viewId] = view;
    }
    return view;
  },
  
  getFirstSelectedViewId: function CP_getFirstSelectedViewId() {
    var firstViewId = null;
    for(var i=0;i < this.product.views.list.size(); i++) {
      var pView = this.product.views.list[i];
      var cView = this.getView(pView.id, false);
      if((cView != null)&&(cView.isUsed())) {
        return pView.id;
      }
      if((firstViewId == null)&&(pView.allowDesign)) {
        firstViewId = pView.id;
      }
    }
    return firstViewId;
  },
  
  
  getNextItemId: function CP_getNextItemId() {
    return d.getNextItemId(); //proxy to designer to make ids cart wide...
  },
  
  registerServerItemId: function CP_registerServerItemId(id) {
    return d.registerServerItemId(id); //proxy to designer to make ids cart wide...
  },
  
  //get the configured size field
  getSelectedSize: function() {
    if(this.product.type.sizeField != null) {
      return this.cFields[this.product.type.sizeField.id];
    }
    return null;
  },
  
  getSelectedColor: function CP_getSelectedColor() {
    var f = this.product.type.colorField;
    if(f != null) {
      var c = (this.selectedColorId==null) ? null :  this.product.colors.byId[this.selectedColorId];
      if(c != null) {
        return c;
      }
      //no color selected... lets get the default....
      this.selectedColorId = this.product.defaultColor.id;
      return this.product.defaultColor;
      
    } else {
      log("product has no color field");
    }
    return null;
  },
  
  getSelectedColorId: function CP_getSelectedColorId() {
    var sc = this.getSelectedColor();
    if(sc == null) {
      log("product has no color");
      return null;
    }
    return sc.id;
  },
  
  getAvailableColorList: function CP_getAvailableColorList() {
    var colors = null;
    
    if(this.usingCustomProduct()) {
      colors = this.customProduct.getColors();
    } else {
      colors = this.product.colors;
    }
    var sizeField = this.getSelectedSize();
    var result = [];
    if((this.product.limitSizeColors)&&(sizeField != null)) {
      //check that the colors are available for the selected size(s)
      for(var i=0;i < colors.list.length; i++) {
        var pColor = colors.list[i];
        var allAvailable = true;
        for(var sizeId in sizeField.options) {
          var sizeChoice = sizeField.options[sizeId];
          if((sizeChoice.qty > 0)&&(!sizeChoice.def.isMulti)) {
            var sizeColors = this.product.sizeColorCombinations[sizeId];
            if(sizeColors != null) { 
              if(sizeColors[pColor.productChosenOptionId] != true) {
                allAvailable = false;
                log("color " + pColor.productChosenOptionId + " is not available in size " + sizeId); 
                break;
              }
            } else {
              log("Error: size " + sizeId + " has no scc entries");
            }
          }
        }
        if(allAvailable) {
          result.push(pColor);
        }
      }
    } else {
      result = colors.list;
    }
    //check if amending.. only allow same color type so we cannot affect price...
    if(d.mode == DESIGNER_MODE_AMEND) {
      var curColorType = this.getSelectedColor().color_type;
      var result2 = [];
      for(var i=0; i < result.length; i++) {
        if(result[i].color_type == curColorType) {
          result2.push(result[i]);
        }
      }
      return result2;
    }
    
    return result;
  },
  /*
  we can now use the supplier_chosen_color_id to get images
  getSelectedProductColorId: function CP_getSelectedProductColorId() {
    var sc = this.getSelectedColor();
    if(sc == null) {
      log("product has no color");
      return null;
    }
    return sc.productChosenOptionId;
  },*/
  
  //the user has changed the color from the interface
  selectColor: function CP_selectColor(color) {
    var f = this.product.type.colorField;
    log("setting color to " + color.id);
    this.selectedColorId = color.id;
    this.setReRender();
    this.updateThumbnails();
    d.currentCView.setDesignerBackground();
    
    var sizeField = this.getSelectedSize();
    if((this.product.limitSizeColors)&&(sizeField != null)) { //need to rerender the size field because of color change...
      this.product.type.fields.byId[sizeField.id].setField(this);
    }
    
    this.price = null;
    d.currentProductType.updatePrice();
  },
  
  //check if any design work will transfer across (if any exists) so we can warn user of loss of art...
  productChangeWillMatch: function CP_productChangeWillMatch(product) {
    //store old views in an ordered array
    var oldViews = [];
    var wasUsing = false;
    for(var i=0; i < this.product.views.list.size(); i++) {
      var view = this.product.views.list[i];
      oldViews[i] = this.views[view.id];
      if((oldViews[i] == null || !oldViews[i].isUsed()) && (this.stash != null) && (this.stash[i] != null)) {
        oldViews[i] = this.stash[i]; //we are not using the view.. there is one from the stash.. lets use it...
      }
    }
    for(var v in this.views) {
      if(this.views[v].isUsed()) {
        wasUsing = true;
      }
    }
    if(!wasUsing) {
      log("productChangeWillMatch: no designs were being used");
      return 0; //no designs used.. ok to change without warning...
    }
    var moveResult = -1;
    for(var i=0; i < product.views.list.size(); i++) {
      var view = product.views.list[i];
      if(oldViews[i] != null) {
        //we can use a view from the same position....
        var newCView = new ConfiguredView(this,view, {isTempView:true});
        var mR = newCView.moveToView(oldViews[i], true);//called with testOnly=true to test move
        if(moveResult < mR) {
          moveResult = mR;
        }
      }
    }
    return moveResult; 
  },
  
  //when the product changes for this configured product... type and match up product data to be user friendly....
  setProduct: function CP_setProduct(product) {
    var oldProduct = this.product;
    this.product = product;
    if(oldProduct != null) {
      
      //move the field choices across...
      this.selectedColorId = null;
      var oldFields = this.cFields;
      this.initFields();
      
     for(var i=0; i < this.product.type.fields.list.length; i++) {
        var fieldDef = this.product.type.fields.list[i];
        if(fieldDef.code != "C") {
          var newField = this.cFields[fieldDef.id];
          if(newField != null) {
            var oldFieldDef = oldProduct.type.fieldsByCode[fieldDef.code];
            if(oldFieldDef==null) { 
                oldFieldDef = oldProduct.type.fieldsByName[fieldDef.name];
                if(oldFieldDef != null) {
                  log("setProduct: field with name " + fieldDef.name + " is in both products");
                }
            } else{
              log("setProduct: field with code " + fieldDef.code + " is in both products");
            }
            if(oldFieldDef != null) {
              //field exists in both types..
              oldCField = oldFields[oldFieldDef.id];
              if(oldCField != null) {
                newField.initFromPreviousSelection(oldCField);
              } else {
                log("setProduct: field with code " + fieldDef.code + " is missing from oldProduct");
              }
            }
            newField.refreshHtml();
          }
        }
      }
      this.setQtyFromMulti();
      
      
      this.initFieldDefaults();
      
      //for each view that is used
      log("Setting Product" );
      log(product);
      log(oldProduct);
      
      
      //store old views in an ordered array
      var oldViews = [];
      for(var i=0; i < oldProduct.views.list.size(); i++) {
        var view = oldProduct.views.list[i];
        oldViews[i] = this.views[view.id];
        if((oldViews[i] == null || !oldViews[i].isUsed()) && (this.stash != null) && (this.stash[i] != null)) {
          oldViews[i] = this.stash[i]; //we are not using the view.. there is one from the stash.. lets use it...
          log("Using stashed view for " + view.name + " pos=" + i);
        }
      }
      
      this.views = {};
      //go through the views in order.. use order to match....
      for(var i=0; i < this.product.views.list.size(); i++) {
        var view = this.product.views.list[i];
        if(oldViews[i] != null) {
          //we can use a view from the same position....
          var newCView = this.getView(view.id, true);
          newCView.moveToView(oldViews[i]);
          //oldViews[i] = null;
        }
      }
      //do we want to try and fill views from stuff in oldViews?... for now we wont do the order of views wont change around...
      
      //keep the oldViews arounf
      //anything in oldViews needs to be cleaned up...
      for(var i=0; i < oldViews.length; i++) {
        if(oldViews[i] != null) {
          oldViews[i].remove(); 
        }
      }
      this.stash = null; //oldViews; DONT STASH VIEWS ANYMORE: confusing to customers...
      
      
      
      
    } else {
      this.initFields();
      this.initFieldDefaults();
      this.selectedColorId = null;
    }
    
  },
  
  //called after moving views between products and the view thumbnails are rendered to add the warning against....
  afterProductChanged: function CP_afterProductChanged() {
    this.callServerToRenderThumbnails();
    for(var k in this.views) {
      this.views[k].validate();
    }
  },
  

  getPercentMarkup: function CP_getPercentMarkup(forcePercent) {
    var percentMarkup = 1;
    if((forcePercent == true) || (!this.usingCustomProduct() && this.markupMode == 0)) {
      percentMarkup =  1 + this.markupAmount / 100;
      log("Percent Markup=" + percentMarkup);
    }
    return percentMarkup;
  },
  
  getFixedMarkup: function CP_getFixedMarkup() {
    var fixedMarkup = 0;
    if(this.usingCustomProduct()) {
      fixedMarkup = this.customProduct.markup;
      log("Fixed Custom Product Markup=" + fixedMarkup);
    } else if(this.markupMode == 1) {
      fixedMarkup = this.markupAmount;
      log("Fixed Markup=" + fixedMarkup);
    } else if(this.markupMode != 0) {
      fixedMarkup = this.customProduct.markupAmount;
      log("Fallback Fixed Custom Product Markup=" + fixedMarkup);
    }
    return fixedMarkup;
  },
  
  getUnitPrice: function CP_getUnitPrice() {
    var percentMarkup = this.getPercentMarkup();
    var fixedMarkup = this.getFixedMarkup();
    log("percentMarkup= " + percentMarkup + " fixedMarkup=" + fixedMarkup);
    log("Branding is :"+this.brandId);
    var color = this.getSelectedColor();
    
    var colorType = 0;
    if(color != null) {
      colorType = color.color_type;
      log("Color not null, colorType = " + colorType);
    } else {
      log("Color NULL!, colorType = " + colorType);
    }
    
    var cost = 0;
    
    if(colorType == 0 || this.product.type.pricingType == PRICE_TYPE_FLAT) {
      cost = parseFloat(this.product.price[0]);
		} else {
			cost = parseFloat(this.product.price[colorType]);
		}
    
    var basePrice = cost * percentMarkup + fixedMarkup;
    
    var baseColorDelta = (cost - this.product.price[0]) * percentMarkup;
    
    
    var basePriceWithDecoration = basePrice;
    var baseCostWithDecoration = cost;
    
    
    log("basePrice=" + basePrice + " cost=" + cost);
    
    var pricingData = {
      basePrice: basePrice,
      baseColorDelta: baseColorDelta,
      basePriceWithDecoration: basePrice,
      baseCostWithDecoration: cost,
      unUsedDecorationCost: 0.0,
      baseCost: cost,
      extras: [],
      decorationPrice: 0.0,
      decorationCost: 0.0
    };
    
    var fieldDecorationCost = 0.0;
    //init the base price to include the first area price that can use the selected process
    if((!this.hasDecorations()) && this.defaultProcessId != -1 && d.userSelectedProcessId != -1) { //as soon as we have started decorating we no longer use default prices...
      log("No Customising Done: Using default decoration prices from process " + this.defaultProcessId);
      for(var i =0; i < this.product.views.list.size(); i++) {
        var pView = this.product.views.list[i];
        var noUsageProcess = pView.getDefaultPricingProcess(this.defaultProcessId);
        if(noUsageProcess != null) {
          var cost = noUsageProcess.getDefaultDecorationPrice(colorType);
          log("Default Decoration Cost:" + cost);
          pricingData.basePriceWithDecoration += (cost * percentMarkup);
          pricingData.baseCostWithDecoration += cost;
          //keep track of this amount so we can take it from any decoration pricing....
          pricingData.unUsedDecorationCost = cost;
          fieldDecorationCost = cost;
          break;
        } else {
          log("noUsageProcess not found");
        }
      }
    } else {
      //update the decoration cost
      var decorationPrice = 0;
      var decorationCost = 0;
      for(var i =0; i < this.product.views.list.size(); i++) {
        var pView = this.product.views.list[i];
        var cView = this.views[pView.id];
        if((cView != null) && (cView.isUsed())) {
          decorationCost += cView.calculatePrice(colorType, pricingData, percentMarkup);
        } 
      }
      fieldDecorationCost = decorationCost
      decorationPrice = decorationCost * percentMarkup;
      log("decorationCost=" +decorationCost + ", decorationPrice=" + decorationPrice);
      pricingData.decorationPrice = decorationPrice;
      pricingData.decorationCost = decorationCost;
    }
    
    var unitPrice = pricingData.basePriceWithDecoration + pricingData.decorationPrice;
    var unitCost = pricingData.baseCostWithDecoration + pricingData.decorationCost;
    
    
    //get the prices for field choices
    
    var fieldCost = this.fieldPrice(colorType, fieldDecorationCost, pricingData.baseCost, pricingData); //we use costs becuase the markup will be applied to the results
    unitCost += fieldCost;
    var fieldPrice = fieldCost * percentMarkup;
    unitPrice += fieldPrice;
    log("field cost=" + fieldCost + ", fieldPrice=" + fieldPrice);
    //round to full cents...
    unitPrice = parseFloat(Math.round(unitPrice * 100.0) / 100);
    unitCost = parseFloat(Math.round(unitCost * 100.0) / 100);
    log("final unit price=" + unitPrice + " cost=" + unitCost);
    this.price = d.roundPrice(unitPrice);
    this.cost = unitCost;
    log("final rounded price=" + this.price);
    
    
    log(pricingData);
    return this.price;
  },
  
  fieldPrice: function(colorIdx, decorationPrice, basePrice, pricingData) {
    log("fieldPrice for colorIdx=" + colorIdx);
    var fixedMarkups = {};
    var percentMarkups = {};
    var finalMarkups = {};
    //sum defaults for the fields...
   
    
    var fieldPricingData = {};
    
    //determine the fixed/percent markups for each field
    for(var i=0; i < this.product.fields.list.size(); i++) {
      var pField = this.product.fields.list[i];
      if(pField.fieldDef.fieldType != FIELD_TYPE_PRODUCT_COLOR) {
        var fieldDef = pField.fieldDef;
        var cField = this.cFields[fieldDef.id];
        var priceModifierType = fieldDef.priceModifierType;
        if (priceModifierType != PRICE_MODIFY_NONE) {
          var fieldPriceData = {
            type: 4,
            field: cField,
            extras: []
          };
          fieldPricingData[fieldDef.id] = fieldPriceData;
          pricingData.extras.push(fieldPriceData);
          var fieldMarkup = 0.0;
          var fieldQty = 0;
          if(fieldDef.typeOptions.list) {
            var selectedOptions = cField.getSelectedOptions(true);
            var fieldColorIdx = (fieldDef.pricingType == PRICE_TYPE_FLAT) ? 0 : colorIdx;
            for(var j=0; j < selectedOptions.length; j++) {
              var cChoice = selectedOptions[j];
              var priceModifierToUse = pField.usePriceDefaults ? cChoice.def.defaultPrices : cChoice.pDef.priceDelta;
              var choicePrice = priceModifierToUse[fieldColorIdx]==null ? 0 : priceModifierToUse[fieldColorIdx];
              choicePrice = parseFloat(choicePrice);
              var optPriceData = {
                type: 5,
                option: cChoice,
                qty: null,
                total: choicePrice
              };
              if(cField.multiSelect) {
                fieldMarkup += choicePrice * cChoice.qty;
                fieldQty += cChoice.qty;
                optPriceData.qty = cChoice.qty;
              } else {
                fieldMarkup += choicePrice;
              }
              fieldPriceData.extras.push(optPriceData);
            }
            if(cField.multiSelect) {
              fieldMarkup = fieldMarkup / fieldQty;
            }
          } else if(cField.isUsed()) {
            var priceModifierToUse = pField.usePriceDefaults ? fieldDef.priceModifier : pField.priceDelta;
            var choicePrice = priceModifierToUse[fieldColorIdx]==null ? 0 : priceModifierToUse[fieldColorIdx];
            fieldMarkup += parseFloat(choicePrice);
          }
          if(priceModifierType == PRICE_MODIFY_FIXED) {
            fixedMarkups[fieldDef.id] = fieldMarkup;
            log(fieldDef.name + " has a fixed markup of " + fieldMarkup);
          } else {
            percentMarkups[fieldDef.id] = fieldMarkup;
            log(fieldDef.name + " has a percent markup of " + fieldMarkup + "%");
          }
        }
      }
    }
    fixedMarkups[-1] = basePrice;   
    fixedMarkups[-2] = decorationPrice;  

    var totalFieldMarkup = 0.0;
    
    for(var i=0; i < this.product.fields.list.size(); i++) {
      var pField = this.product.fields.list[i];
      if(pField.fieldDef.fieldType != FIELD_TYPE_PRODUCT_COLOR) {
        var fieldDef = pField.fieldDef;
        var cField = this.cFields[fieldDef.id];
        var priceModifierType = fieldDef.priceModifierType;
        if (priceModifierType != PRICE_MODIFY_NONE) {
          fieldPriceData = fieldPricingData[fieldDef.id];
          var fieldMarkup = 0.0
          if(priceModifierType == PRICE_MODIFY_FIXED) {
             fieldMarkup = fixedMarkups[fieldDef.id];
          } else {
            var thisPercent = percentMarkups[fieldDef.id];
            //we need to apply a percentage to the selected fixed fields
            for(var j=0; j < fieldDef.percentOf.length; j++) {
              var percentOfId = fieldDef.percentOf[j]
              var fixedMarkup = fixedMarkups[percentOfId];
              if(fixedMarkup == null) {
                log("Unable to get fixed markup for field " + percentOfId);
              } else {
                log("Adding " + thisPercent + "% of " + fixedMarkup + " for field " + percentOfId);
                fieldMarkup += (fixedMarkup * thisPercent / 100.0);
              }
            }
          }
          log("Calcing Field Markup, " + fieldDef.name + " adds $" + fieldMarkup);
          fieldPriceData.total = parseFloat(fieldMarkup);
          totalFieldMarkup += fieldPriceData.total;
        }
      }
    }
    return totalFieldMarkup;
  },
  
  getPrice: function CP_getPrice() {
    if(this.cp_type == CP_DIGITIZATION) {
      return this.price;
    } else {
      if(this.price == null) {
        this.getUnitPrice();
      }
      
      this.discount = d.getDiscount(this.qty, this.price, this.cost);
      log("discount=" + this.discount);
      return (this.price * this.qty) - this.discount;
    }
  },
  
  getCurPrice: function CP_getCurPrice() {
    this.getPrice() * d.cMod;
  },
  
  getCurDiscount: function CP_getCurDiscount() {
    this.discount * d.cMod;
  },
  
  multiOptionField: function CP_multiOptionField() {
    for(var k in this.cFields) {
      if(this.cFields[k].multiSelect) {
        return this.cFields[k];
      }
    }
    return null;
  },
  
  serialize: function CP_serialize(queryComponents, prefix, viewId, forSave) {
    if(prefix==null) {
      prefix="c[" + this.id + "]";
    }
    if(queryComponents==null) {
      queryComponents = new Array();
    }
    log(this);
    this.serializingForSave = forSave;
    queryComponents.push(encodeURIComponent(prefix + "[p]") + "=" + encodeURIComponent(this.product.id));
    queryComponents.push(encodeURIComponent(prefix + "[q]") + "=" + encodeURIComponent(this.qty));
    queryComponents.push(encodeURIComponent(prefix + "[lv]") + "=" + encodeURIComponent(this.renderVersion));
    queryComponents.push(encodeURIComponent(prefix + "[c]") + "=" + encodeURIComponent(this.getSelectedColorId()));
    queryComponents.push(encodeURIComponent(prefix + "[def_proc]") + "=" + encodeURIComponent(this.defaultProcessId));

    if(this.usingCustomProduct()) {
      queryComponents.push(encodeURIComponent(prefix + "[cp]") + "=" + encodeURIComponent(this.customProductId));
    }
    
    var self = this;
    for(var i=0; i < this.product.fields.list.size(); i++) {
      var pField = this.product.fields.list[i];
      if(pField.fieldDef.code != "C") { //ignore color field
        var cField = this.cFields[pField.id];
        cField.serialize(queryComponents, prefix + "[f][" + pField.id + "]");
      }
    }
    if(d.mode != DESIGNER_MODE_VIEW_CUSTOM_PRODUCT) {
      for(var k in this.views) {
        view = this.views[k];
        if((view.isUsed())&&((viewId==null)||(viewId == view.id))) {
          var p = prefix + "[v][" + view.id + "]";
          view.serialize(queryComponents, p);
        }
      }
    }
    if(forSave == true && this.teamNames != null && this.usingTeamnames) {
      queryComponents.push(encodeURIComponent(prefix + "[utn]") + "=1");
      this.teamNames.serialize(queryComponents, prefix + "[tn]");
    }
    this.serializingForSave = false;
    return queryComponents.join('&');
  },
  
  save: function CP_save(force) {
    if(this.qty <= 0) {
      alert(ml("You must specify a valid quantity to add this product to the cart"));
      return;
    }
    var self = this;
    
    this.checkForAlerts(false, function(result) {
      if(result) {
        var self = this;
        var aKey = null;
        var cont = null;
        this.product.type.itemSaved();
        
        if(this.addedToCart) {
          d.track("update-edited-product");
          cont = "cart_" + this.id;
          
          ajaxQueueManager.queueRequest("save_product/" + this.id, 1, {
              mode: 0,
              url: d.pathPrefix + "/designer/save_product",
              target: "cart_" + this.id,
              parameters: function CP_parameters() { return self.serialize([],null, null, true);},
              options: {asynchronous:true, evalScripts:true, 
                onFailure: function CP_onFailure() {
                  alert(ml("An error occured on the server. The development team has been notified. Sorry for any inconvenience."));
                },
                onComplete: function CP_onComplete() { 
                  log("save product complete after update edit product");
                  asyncFinish(aKey);
                  d.notifyCartChanged();
                  d.cart.selectCartItem(d.currentCProduct); 
                  processToolTips($(cont));
                }
              }
          });
          
        } else {
          d.track("save-new-product");
          cont = "m_cart_pane";
          
          ajaxQueueManager.queueRequest("save_product/" + this.id, 1, {
              mode: 0,
              url: d.pathPrefix + "/designer/save_product?is_new=1",
              target: "cart_body",
              parameters: function CP_parameters() { return self.serialize([],null, null, true);},
              options: {asynchronous:true, evalScripts:true, insertion: Insertion.Bottom,
                /*
                Moved to saveCallback called by server response
                onSuccess: function CP_onSuccess() {
                  self.addedToCart = true; 
                  d.notifyCartChanged();
                  if(d.currentCProduct == self) {
                    self.product.type.showEditing(true);
                  }
                },*/
                onFailure: function CP_onFailure() {
                  alert(ml("An error occured on the server. The development team has been notified. Sorry for any inconvenience."));
                },
                onComplete: function CP_onComplete() { 
                  log("save product complete after save new product");
                  asyncFinish(aKey);
                  d.cart.selectCartItem(d.currentCProduct);
                  processToolTips($("cart_body"));
                }
              }
          });
        }
        var cartTab = $("m_cart");
        if(cartTab.className == "unselected_tab_hidden") {
          cartTab.className = "unselected_tab";
        }
        d.selectTab('m','cart');
        aKey = asyncStart($(cont));
      }
    }.bind(this));
  },
  
  saveCallback: function CP_saveCallback(errorsOccured) {
    if(errorsOccured) {
      this.checkForAlerts(false, function() {}); //show the error...
    } else {
        this.addedToCart = true; 
        d.notifyCartChanged();
        try {
          if(updateCart) updateCart();
        } catch(e) {
          //doesnt matter (this would update cart at top of page.. must be there...)
        }
        
        if(d.currentCProduct == this) {
          this.product.type.showEditing(true);
        }
    }
  },
  
  //will check for alerts, if ignoreWarnings only stops on errors
  //calls callback with true if all ok, false if the save should stop...
  checkForAlerts: function CP_checkForAlerts(ignoreWarnings, callback) {
    this.checkCallback = callback;
    var types = [0];
    if(!ignoreWarnings) {
      types.push(1);
    }
    
    log("Checking for alerts");
    var allAlertTypes = {"quality_warning":true, "crop_error":true, "overlap_error":true, "crop_warning":true};
    
    var alerts = this.getAlerts(types);
    var alertIndex = -1;
    if(hashSize(alerts[0]) > 0) { //errors.. dont bother with warnings...
      $("alert_warning_has_errors").style.display="";
      $("alert_warning_no_errors").style.display="none";
      $("alert_warning_error_icon").style.display="";
      $("alert_warning_warning_icon").style.display="none";
      alertIndex = 0;
    } else if(hashSize(alerts[1]) > 0) { //no errors.. show warnings...
      $("alert_warning_has_errors").style.display="none";
      $("alert_warning_no_errors").style.display="";
      $("alert_warning_error_icon").style.display="none";
      $("alert_warning_warning_icon").style.display="";
      alertIndex = 1;
    }
    if(alertIndex == -1) {
      this.checkCallback(true);
    } else {
      for(var k in alerts[alertIndex]) {
        var error = alerts[alertIndex][k];
        $(k + "_div").style.display="";
        delete allAlertTypes[k]; //track its been used..
        var images = $(k + "_images_list"); //remove existing images...
        while(images.childNodes.length > 0) {
          images.removeChild(images.childNodes[0]);
        }
        
        for(var i=0; i < error.items.length; i++) {
          var item = error.items[i];
          var thumb = document.createElement("Img");
          thumb.src = item.errorThumb;
          thumb.width = item.width;
          thumb.height = item.height;
          images.appendChild(thumb);
        }
        //clear unused types
        for(var k in allAlertTypes) {
          $(k + "_div").style.display="none";
        }
      }
      popup('alert_warning');
    }
  },
  
  alertCheckFinished: function CP_alertCheckFinished(result) {
    closePopup('alert_warning') ;
    this.checkCallback(result);
  },
  
  //go through the items get any item with alerts of {types}
  getAlerts: function CP_getAlerts(types) {
    var alerts = [{},{},{}];
    for(k in this.views) {
      view = this.views[k];
      if(view.isUsed()) {
        for(var ak in view.areas) {
          var area = view.areas[ak];
          if(area.isUsed()) {
            log("Check for alerts in area " + area.productArea.getName());
            for(var ik in area.allItems) {
              var item = area.allItems[ik];
              
              item.getAlerts(types, alerts);
            }
          }
        }
      }
    }
    return alerts;
  },
  
  //set an icon against the add/update button and views if there is a warning/error
  setAlertIcons: function CP_setAlertIcons() {
    if(d.mode==DESIGNER_MODE_VIEW_CUSTOM_PRODUCT) return; //viewing custom product
    var minAlert = 4;
    for(var i=0; i < this.product.views.list.size(); i++) {
      var pView = this.product.views.list[i];
      
      var view = this.views[pView.id] ;
      var minViewAlert = 4;
      if(view != null && view.isUsed()) {
        for(var ak in view.areas) {
          var area = view.areas[ak];
          if(area.isUsed()) {
            for(var ik in area.allItems) {
              var item = area.allItems[ik];
              if(item.alertLevel != null && item.alertLevel < minAlert) {
                minAlert = item.alertLevel;
              }
              if(item.alertLevel != null && item.alertLevel < minViewAlert) {
                minViewAlert = item.alertLevel;
              }
            }
          }
        }
      }
      if((pView.allowView)&&(pView.allowDesign)) {
        log(pView);
        var viewEl = $("d_l_s_" + pView.id);
        if(viewEl !=null) {
          if(minViewAlert == 1) { //warning
            $("d_l_s_" + pView.id).className = "d_layout_warning";
          } else if(minViewAlert == 0) {//error  
            $("d_l_s_" + pView.id).className = "d_layout_error";
          } else {                               
            $("d_l_s_" + pView.id).className = "d_layout_noalert";
          }
        }
      }
    }
    if(minAlert == 1) { //warning
      $("add_cart_container").className = "d_g_button_warning";
      $("update_cart_button_container").className = "d_g_button_warning";
    } else if(minAlert == 0) {//error
      $("add_cart_container").className = "d_g_button_error";
      $("update_cart_button_container").className = "d_g_button_error";
    } else {
      $("add_cart_container").className = "d_g_button_noalert";
      $("update_cart_button_container").className = "d_g_button_noalert";
    }
  },
  
  
  usingCustomProduct: function CP_usingCustomProduct() {
    if((this.customProduct != null)&&(this.customProduct.productId == this.product.id)) {
      return true;
    }
    return false;
  },
  
  hasDecorations: function CP_hasDecorations() {
    //we still need to check the views because they may have deleted everything so we need to show the "unused price"
    for(var k in this.views) {
      view = this.views[k];
      if(view.isUsed()) {
        return true;
      }
    }
    return false;
  },
  
  isCustomised: function CP_isCustomised() {
    if(this.layout_version == 0) {//when its a custom product there will be used views yet the product has not been customised...
      return false;
    }
    //we still need to check the views because they may have deleted everything so we need to show the "unused price"
    for(var k in this.views) {
      view = this.views[k];
      if(view.isUsed()) {
        return true;
      }
    }
    return false;
  },
  
  
  saveFromView: function CP_saveFromView() {
    var self = this;
    var aKey = null;
    var cont = null;
    this.product.type.itemSaved();
    cont = "pt_info_" + this.product.type.id;
    if(this.addedToCart) {
      var t2 = new Ajax.Updater("cart_notice", d.ajaxUrl(d.pathPrefix + "/designer/save_product?for_view=1"), {asynchronous:true, evalScripts:true, parameters:this.serialize([],null), 
        onComplete: function CP_onComplete() { 
          asyncFinish(aKey);
          d.notifyCartChanged();
          popup("cart_notice");
          try {
            if(updateCart) updateCart();
          } catch(e) {
            //doesnt matter (this would update cart at top of page.. must be there...)
          }
        }
      });
    } else {
      var t2 = new Ajax.Updater("cart_notice",d.ajaxUrl(d.pathPrefix + "/designer/save_product?for_view=1&is_new=1"), {asynchronous:true, evalScripts:true, parameters:this.serialize([],null), 
        onComplete: function CP_onComplete() { 
          asyncFinish(aKey);
          d.notifyCartChanged();
          popup("cart_notice");
          try {
            if(updateCart) updateCart();
          } catch(e) {
            //doesnt matter (this would update cart at top of page.. must be there...)
          }
        }
      });
    }
    aKey = asyncStart($(cont));
  },
  
  saveWorkingVersion: function CP_saveWorkingVersion() {
    $("dynamic_popup").innerHTML = "<br/><br/>Saving..<br/><br/>";
    var aKey = null;
    var t2 = new Ajax.Updater({ success: 'dynamic_popup' }, d.ajaxUrl(d.pathPrefix + "/designer/save_working_version"), {asynchronous:true, evalScripts:true, parameters:this.serialize([],null), 
      onComplete: function CP_onComplete() { 
        asyncFinish(aKey);
        repositionPopup("dynamic_popup");
      },
      onFailure: function CP_onFailure() {
        alert(ml("Server Error Occured"));
        closePopup("dynamic_popup");
      }
    });
    $("dynamic_popup").style.width="400px";
    popup("dynamic_popup");
    aKey = asyncStart($("dynamic_popup"));
  },
  
  email: function CP_email() {
    $("dynamic_popup").innerHTML = "<br/><br/>Saving..<br/><br/>";
    var aKey = null;
    var t2 = new Ajax.Updater({ success: 'dynamic_popup' }, d.ajaxUrl(d.pathPrefix + "/designer/email"), {asynchronous:true, evalScripts:true, parameters:this.serialize([],null), 
      onComplete: function CP_onComplete() { 
        asyncFinish(aKey);
        repositionPopup("dynamic_popup");
      },
      onFailure: function CP_onFailure() {
        alert(ml("Server Error Occured"));
        closePopup("dynamic_popup");
      }
    });
    $("dynamic_popup").style.width="650px";
    popup("dynamic_popup");
    aKey = asyncStart($("dynamic_popup"));
  },
  
  showPreview: function CP_showPreview() {
    $("dynamic_popup").innerHTML = "<br/><br/>Generating..<br/><br/>";
    var aKey = null;
    var t2 = new Ajax.Updater({success:"dynamic_popup"}, d.ajaxUrl(d.pathPrefix + "/designer/save_product?big_preview=1"), {asynchronous:true, evalScripts:true, parameters:this.serialize([],null), 
      onComplete: function CP_onComplete() { 
        asyncFinish(aKey);
      },
      onSuccess: function CP_onSuccess() {
        repositionPopup("dynamic_popup");
      },
      onFailure: function CP_onFailure() {
        closePopup("dynamic_popup");
        alert(ml("An error occured processing preview"));
      }
    });
    $("dynamic_popup").style.width="";
    popup("dynamic_popup");
    aKey = asyncStart($("dynamic_popup"));
  },
  
  bindCart: function CP_bindCart() {
    log("Binding Cart Item " + this.id);
    this.cartQtyBox = $("cart_qty_" + this.id);
    this.cartPrice = $("cart_price_" + this.id);
    if(this.cartQtyBox != null) {
      var self = this;
      this.cartQtyBox.onkeyup = function() {
        d.itemChanged();
        self.updateQty(self.cartQtyBox.value, true);
      } ;
    } else {
      log("bindCart: No cart qty el for " + this.id);
    }
    if(this.cartPrice==null) {
      log("No Cart Price Element cart_price_" + this.id);
    } else {
      log(this.cartPrice);
    }
  },
  
  //make sure qty follows min qty/bundle rules...
  checkQty: function CP_checkQty(qty, updateQtyEl, updateCartEl) {
    var rQty = qty;
    if(this.product.usesMinQty()) {
      if(qty < this.product.minQty) {
        rQty = this.product.minQty;  
      } else {
        var extraQty = qty - this.product.minQty;
        var bundles = parseInt(extraQty / this.product.bundleSize);
        extraQty = bundles * this.product.bundleSize;
        rQty = this.product.minQty + extraQty;
      }
      if(rQty != qty) {
        if(updateQtyEl) {
          if(d.currentCProduct == this) {
            $("qty").value = rQty;
          }
        }
        if(updateCartEl) {
          if(this.cartQtyBox!=null) {
            this.cartQtyBox.value = rQty;
          }
        }
      }
    }
    return rQty;
  },
  
  updateQty: function CP_updateQty(value, fromCart) {
    if(this.multiOptionField()==null) {
      this.qty = parseInt(value, 10);
      if(isNaN(this.qty)) {
        this.qty = 0;
      }
      this.qty = this.checkQty(this.qty, true, true);
      this.updateCartPrice();
      if(fromCart) {
        if(d.currentCProduct == this) {
          $("qty").value = this.qty;
        }
      } else if(this.cartQtyBox!=null) {
        this.cartQtyBox.value = this.qty;
      }
      if(d.currentCProduct == this) {
        $("qty").disabled = d.defaultQtyDisabled;
        this.product.type.updatePrice();
      }
      if(fromCart) {
        //update the backend
        var t2 = new Ajax.Request(d.ajaxUrl(d.pathPrefix + "/designer/update_qty?cpid=" + this.id + "&qty=" + this.qty), {asynchronous:true, evalScripts:true});
      }
    }
  },
  
  
  updateMultiQty: function CP_updateMultiQty(value, fieldId, optionId, subOptionId) { 
    log("updateMultiQty:" + value + " fieldId=" + fieldId + " optionId=" + optionId + " subOptionId=" + subOptionId);
    var qty = parseInt(value, 10);
    if(isNaN(qty)) {
      qty = 0;
    }
    var f = this.cFields[fieldId];
    f.addSelectedOption(optionId, qty, subOptionId);
    f.cleanEmptyOptions();
    this.setQtyFromMulti();
    if(d.currentCProduct == this) {
      this.product.type.updatePrice();
      $("qty").disabled = true;
      $("qty").value = this.qty;
    }
    if(this.product.type.sizeField != null && this.product.type.sizeField.id == fieldId && this.product.limitSizeColors) {
      //we need to rerender the color list as the size selection could have changed available colors..
      this.product.type.buildColorPanel(this);
    }
  },
  
  //calculate the qty from multi selector
  setQtyFromMulti: function CP_setQtyFromMulti() {
    var cField = this.multiOptionField();
    if(cField != null) {
      if(cField.multiSelect) {
        log("Setting QTY For multiple selection data");
        var qty = 0;
        for(var k in cField.options) {
          var opt = cField.options[k];
          if(!opt.def.isMulti) {
            if(opt.pDef.subs != null) {
              qty += opt.subQty;
            } else {
              qty += opt.qty;
            }
          }
        }
        this.qty = qty;
      }
    }
  },
  
  updateCartPrice: function CP_updateCartPrice(skipTotal) {
    if(this.cartPrice!=null) {
      var unitPrice = this.getUnitPrice();
      this.cartPrice.innerHTML = d.formatPrice(this.getPrice());
    } else {
      log("No Cart Price Element for " + this.id);
    }
    if(skipTotal || skipTotal == null) {
      d.cart.updateCartPrice();
    }
  },
  
  remove: function CP_remove() {
    for(var k in this.views) {
      var view = this.views[k];
      view.remove();
    }
  },
  
  //restore state from options
  rollBack: function CP_rollBack() {
    //call the cart to rollback in the same order the cart is listed in to build shared state correctly
    d.cart.rollbackProduct(this);
  },
  
  //called from cart.rollbackProduct in corrent order
  doRollBack: function CP_doRollBack() {
    this.remove();
    this.initialize(this.id, this.options);
    var select = false;
    if(d.selected_tabs["m"] == "customize") {
      select = true;
    }
    d.selectConfiguredProduct(this.id, true, select);
    this.updateQty(this.qty, false);
    this.product.type.itemSaved();
    this.setAlertIcons();
  },
  
  //called by cart to restore any shared state (digitization tracking)
  restoreSharedState: function() {
    for(var vk in this.views) {
      var view = this.views[vk];
      for(var va in view.areas) {
        var area = view.areas[va];
        for(var vi in area.allItems) {
          var item = area.allItems[vi];
          if(item.digitize) {
            item.digitizedAsset = d.cart.registerDigitizedAsset(item);
          }
        }
      }
    }
  },
  
  copy: function CP_copy(src) {
    this.remove();
    this.initialize(this.id, src.options);
    this.addedToCart = false;
    d.selectConfiguredProduct(this.id, true, true);
    this.updateQty(this.qty, false);
    this.product.type.itemSaved();
    this.setAlertIcons();
  },
  
  //called to update the configured product that will be used by the reseller
  saveProduct: function CP_saveProduct() {
    this.checkForAlerts(false, function(result) {
      if(result) {
        var self = this;
        var aKey = null;
        var cont = null;
        
        cont = "designer_container";
        var t2 = new Ajax.Request(d.ajaxUrl(d.pathPrefix + "/designer/save_product?for_product=1"), {asynchronous:true, evalScripts:true, parameters:this.serialize([],null), 
          onSuccess: function() { 
            //asyncFinish(aKey); 
            dontWarnBeforeLeaving = true;
            var ma = ""
            if (window.location.search.indexOf("ma=4") >= 0) ma = "ma=4&"
            window.location = d.pathPrefix + "/cproducts/configure_product?"+ma+"cpid=" + self.id + "&" + d.extraCallbackParams;
          },
          
          onFailure: function() { 
            asyncFinish(aKey); 
            alert(ml("An error occured on the server. The development team has been notified. Sorry for any inconvenience."));
          }
        });
        aKey = asyncStart($(cont));
      }
    });
  },
  
  onLayoutChanged: function CP_onLayoutChanged() {
    if(d.mode == DESIGNER_MODE_CONFIGURE) {
      this.layout_version ++;
    } else {
      this.layout_version += 1000;
    }
  },
  
  //server callback when a view thumbnail is updated
  updateView: function CP_updateView(viewId, src, renderVersion, results) {
    var view = this.views[viewId];
    if(view!=null) {
      view.updateView(src, renderVersion, results);
    } else {
      //could be a derived view....
      var productView = this.product.views.byId[viewId];
      if((productView != null)&&(!productView.allowDesign)) { //it is a derived view...
        view = this.getView(viewId, true); //create one...
        view.updateView(src, renderVersion, results);
      } else {
        log("Update View called on missing view " + viewId);
      }
    }
  },
  
  //choices (sizes) can change the scale and x/y offset. So can the product itself.
  getLayoutModifiers: function CP_getLayoutModifiers() {
    
    var mods = new Hash({s:1, y:0, x:0});
    //depricated
    return mods;
  },
  
  setChildReRender: function CP_setChildReRender() {
    this.reRenderChild = true;
    this.renderVersion ++;
    d.itemChanged();
  },
  
  setReRender: function CP_setReRender() {
    this.reRender = true;
    this.renderVersion ++;
    //flag all the views that are used for rerendering
    for(var k in this.views) {
      var view = this.views[k];
      if(view.isUsed()) {
        view.setReRender(true);
      }
    }
  },
  
  clearReRender: function CP_clearReRender() {
    this.reRenderChild = false;
    this.reRender = false;
    for(var k in this.views) {
      this.views[k].clearReRender();
    }
  },
  
  //update the view thumbnails... called when all views need updating... not just a single view....
  updateThumbnails: function CP_updateThumbnails() {
  /*  logic handled below...
  if(d.mode == DESIGNER_MODE_VIEW_CUSTOM_PRODUCT) { //this can only be a color change...
      //TODO....
      return;
    }
    */
    if((d.mode != DESIGNER_MODE_VIEW_CUSTOM_PRODUCT)&& (this.reRender || this.reRenderChild)) { //the data has changed requiring a rerender... need to regen the thumbnails on the server...
      //call the server to regen the thumbnails...
      this.callServerToRenderThumbnails();
    }
    var colorId = this.getSelectedColorId();
    //set the thumb of all views that dont need a reRender
    for(var i=0; i < this.product.views.list.size(); i++) {
      var productView = this.product.views.list[i];
      if(productView.allowView) {
        var cView = this.getView(productView.id, false);
        var url = null;
        if((cView == null)||(!cView.isUsed())||(d.mode ==DESIGNER_MODE_VIEW_CUSTOM_PRODUCT)) { //the view has no mods...
          if(this.usingCustomProduct()) { //we are using a custom product.. check if we can use the customised view...
            url = this.customProduct.getViewURL(productView.id, 11, colorId, 1);
            log("updateThumbnails: usingCustomProduct= true, url=" + url);
          }
          if(url == null) {
            url = productView.getViewURL(11, colorId, 1); //get the blank version
          }
        } else if(cView.needsReRendering()) {
          //skip this view... waiting for it to be rerendered on the server...
        } else { 
          url = cView.getViewURL(11, true, true); //get the view url based on internal logic ocntained in cView (handle custom product prerendered views)
        }
        if(url != null) {
          var container = $("d_l_" + productView.id);
          var img = $("d_l_i_" + productView.id);
          setImageUrl(container, img, url, null);
        }
      }
    }
  },
  //save this to the server in preview mode to rerender the thumbnails
  callServerToRenderThumbnails: function CP_callServerToRenderThumbnails() {
    var t2 = new Ajax.Request(d.ajaxUrl(d.pathPrefix + "/designer/save_product?preview=1&lcpid=" + this.id ), {asynchronous:true, evalScripts:true, parameters:this.serialize([],null, null)});
  }
});
