// define the steps to a watch


var Params = new Array("series", "color", "movt", "dial", "band", "custom");
var ParamsCount = Params.length;

var NameCollection = new ParamCollection(); // stores the names of the params
var PriceCollection = new ParamCollection(); // stores the prices of the params
var ReferenceCollection = new ParamCollection(); // stores the model reference codes

var ImageCollection = new ParamCollection();

// a standard hash containing usefuls vars. //////////////////////////////////
var _DefaultHash = { 
  basedir : "files/"
  };

function DefaultHash(hash)
{
  for (var key in _DefaultHash)
  {
    hash[key] = _DefaultHash[key];
  }
  return hash;
}

function isArray(obj) {
  return (obj.constructor.toString().indexOf("Array") != -1);
}

// model //////////////////////////////////////////////////////////////////////
var ModelStringDelimiter = "-";

// the constructor 
function Model(data)
{
  if (data == null)
  {
    this.data = new Array();
    for (var i = 0; i < ParamsCount; i++) this.data.push(0);
  }
  else
  {
    if (!data.length == ParamsCount) { alert("Model created with wrong number of parameters"); }
    this.data = data;
  }
}

// some additional ways to create one
function ModelFromParams(series, color, movt, dial, band, custom)
{
  return new Model(new Array(series, color, movt, dial, band, custom));
}

function ModelFromString(modelString)
{
  return new Model(modelString.split(ModelStringDelimiter));
}

function ModelFromHash(hash)
{
  var a = new Array();
  for (var i = 0; i < ParamsCount; i++)
  {
    a[i] = hash[Params[i]];
  }
  return new Model(a);
}

// some functions
Model.prototype.getHash = function()
{
  var result = new Object();
  for (var i = 0; i < ParamsCount; i++)
  {
    result[Params[i]] = this.data[i];
  }
  return result;
}

Model.prototype.getString = function ()
{
  return this.data.join(ModelStringDelimiter);
}

// the getter and setter for all data by string
Model.prototype.getData = function(param)
{
  return this.data[Params.indexOf(param)];
}

Model.prototype.setData = function(param, value)
{
  this.data[Params.indexOf(param)] = value;
}

// the getter and setter for all data by index
Model.prototype.getIndexedData = function(param)
{
  return this.data[param];
}

Model.prototype.setIndexedData = function(param, value)
{
  this.data[param] = value;
}

// some special getters
Model.prototype.getSeries = function() { return this.data[0]; }
Model.prototype.getColor = function() { return this.data[1]; }
Model.prototype.getMovt = function() { return this.data[2]; } 
Model.prototype.getDial = function() { return this.data[3]; }
Model.prototype.getBand = function() { return this.data[4]; }
Model.prototype.getCustom = function() { return this.data[5]; }

// some special setters
Model.prototype.setColor = function(value) { this.data[1] = value; }
Model.prototype.setMovt = function(value) { this.data[2] = value; }
Model.prototype.setDial = function(value) { this.data[3] = value; }
Model.prototype.setBand = function(value) { this.data[4] = value; }
Model.prototype.setCustom = function(value) { this.data[5] = value; }

// translation ////////////////////////////////////////////////////////////////

var Languages = new Array("en", "de", "fr", "gr");
var LanguageFriendlyNames = new Array("English", "Deutsch", "Français", "Ελληνικά");
var LanguagesCount = Languages.length;

var CurrentLanguage = 0;
var InternalLanguage = 1;

function Translation(strings)
{ 
  if (!(typeof strings == "object"))
  {
    var d = strings;
    
    if (d.indexOf("|") > -1)
    {
      strings = d.split("|");
    }
    else
    {
      strings = new Array();
      strings.push(d);
    }
  }
    
  this.many = (strings.length != 1);
  
  if (strings.length != LanguagesCount && this.many) 
  {
    alert("wrong number of language strings given!");
    return;
  }
  
  var addStrings = new Array();
  if (strings[0].indexOf("[") > -1)
  {
    for (var i in strings)
    {
      var a = strings[i].split("[");
      strings[i] = $.trim(a[0]);
      addStrings.push($.trim(a[1].split("]")[0]));
    }
  }
  this.addStrings = addStrings;
  this.add = (addStrings.length > 0);
  
  this.strings = strings;
}

Translation.prototype.getString = function()
{
  // returns the translation based on the currently set language
  return this.strings[this.many ? CurrentLanguage : 0];
}

Translation.prototype.getInternalString = function ()
{
  // returns the translation based on the default language for the team.
  return this.strings[this.many ? InternalLanguage : 0];
}

Translation.prototype.getLanguageString = function (language)
{
  return this.strings[this.many ? language : 0];
}

Translation.prototype.getLanguageAddString = function (language)
{
  return this.add ? this.addStrings[this.many ? language : 0] : "";
}

Translation.prototype.getLanguageHtmlStringWithAdd = function (language)
{
  return this.add ? '<span title="' + this.getLanguageAddString(language) + '">' + this.getLanguageString(language) + '</span>' : this.getLanguageString(language);
}

Translation.prototype.getHtmlString = function ()
{
  // returns all translation marked as <span class=... which will be handled by the js/css trickery
  var result = "";
  if (this.many)
  {
    for (var i = 0; i < LanguagesCount; i++)
    {
      result += '<span class="' + Languages[i] + '">' + this.getLanguageString(i) + '</span>';
    }
  }
  else
  {
    result = this.strings[0];
  }
  return result;
}

Translation.prototype.getHtmlStringWithAdd = function ()
{
  // returns all translation marked as <span class=... which will be handled by the js/css trickery
  var result = "";
  if (this.many)
  {
    for (var i = 0; i < LanguagesCount; i++)
    {
      result += '<span ';
      if (this.add)
      {
        result += 'title="' + this.getLanguageAddString(i) + '" ';
      }
      result += 'class="' + Languages[i] + '">' + this.getLanguageString(i) + '</span>';
    }
  }
  else if (this.add)
  {
    result = '<span title="' + this.addStrings[0] + '">' + this.strings[0] + '</span>';
  }
  else
  {
    result = this.strings[0];
  }
  return result;
}

// the names. this is what will store the names of the params ////////////////

// collection. an object that stores some data (e.g. a translation) as well as a list of children
function Collection(data)
{
  this.data = data;
  this.items = new Array();
} 

function ParamCollection() 
{
  // constructor
  this.collection = new Collection(null);
}

ParamCollection.prototype.getData = function(param, indices) 
// param is the index of the param we want to know.
// indices is a list of the indices for the preciding params. must be at least one element.
{
  if (indices.length < param + 1) { alert("tried to get collection datat with wrong number of preciding params."); return; }
  
  var o = this.collection;
  for (var i = 0; i < param + 1; i++)
  {
    o = o.items[indices[i]];
  }
  
  return o.data;
}

ParamCollection.prototype.setData = function(param, indices, value)
{
  if (indices.length < param + 1) { alert("tried to get collection datat with wrong number of preciding params."); return; }
  
  var o = this.collection;
  for (var i = 0; i < param + 1; i++)
  {
    if (typeof o.items[indices[i]] == "undefined") 
    {
      o.items[indices[i]] = new Collection(null);
    }
    o = o.items[indices[i]];
  }

  o.data = value;  
}

// now this is what finally returns data based on a model object
ParamCollection.prototype.getDataByModel = function(param, model)
{
  return this.getData(param, model.data);
}

ParamCollection.prototype.getDataHashByModel = function(model)
{
  var result = new Object();
  for (var i = 0; i < ParamsCount; i++)
  {
    result[Params[i]] = this.getDataByModel(i, model);
  }
  return result;
}

ParamCollection.prototype.getDataSum = function(param, indices)
{
  var result = 0;
  for (var i = 0; i <= param; i++)
  {
    var v = this.getData(i, indices);
    if (typeof v == "number") result += v;
  }
  return result;
}

ParamCollection.prototype.getDataSumByModel = function(param, model)
{
  return this.getDataSum(param, model.data);
}

// to iterate through the items at a certain step
ParamCollection.prototype.getItems = function(param, indices)
{
  if (indices.length < param) { alert("tried to get collection datat with wrong number of preciding params."); return; }
  
  var o = this.collection;
  for (var i = 0; i < param; i++)
  {
    o = o.items[indices[i]];
  }
  
  result = new Array();
  o = o.items;
  for (var i = 0; i < o.length; i++)
  {
    result.push(o[i].data);
  }
  return result;
}

ParamCollection.prototype.getItemsByModel = function(param, model)
{
  return this.getItems(param, model.data);
}

// and now something which makes a hash of strings of a hash of translations. 
function GetTranslationHash(hash)
{
  var result = new Object();
  for (var key in hash)
  {
    //it is assumed that every item of the hash is a translation.
    result[key] = hash[key].getString();
  }
  return result;
}

function GetTranslationHashInteral(hash)
{
  var result = new Object();
  for (var key in hash)
  {
    //it is assumed that every item of the hash is a translation.
    result[key] = hash[key].getInternalString();
  }
  return result;
}

// this allows to directly generate hidden form code from a hash
function GetHiddenFormCode(hash)
{
  var result = "";
  for (var key in hash)
  {
    result += '<input type="hidden" name="' + key + '" value="' + hash[key] + '" />';
  }
  return result;
} 

function GetFormHash(form)
{
  var result = new Object();
  form.find("input[name][value][type!=radio], input[name][value][checked], select[name], textarea[name]").each(function() 
  {
      result[$(this).attr("name")] = $(this).val();
  });
  
  return result;
}

// custom service class. this looks like a name, but stores additional data!
// number = bit field with each bit indicating if the corresponding service is brought out
// 0  no custom
// 1  only bottom engraving
// 2  only case engraving
// 3  both
function CustomService(number, limit1, limit2)
{
  this.number = number;
  if (this.hasService1())
  {
    this.textLimit1 = limit1;
    if (this.hasService2())
    {
      this.textLimit2 = limit2; 
    }
    else
    {
      this.textLimit2 = null; 
    }
  }
  else if (this.hasService2())
  {
    this.textLimit1 = null;
    this.textLimit2 = limit1; // because so I don't need to pass a meaningless parameter in the constructor.
  }
  else
  {
    this.textLimit1 = null;
    this.textLimit2 = null;
  }
}

CustomService.prototype.hasService1 = function() 
{
  return (this.number == 1 || this.number == 3);
}

CustomService.prototype.hasService2 = function()
{
  return (this.number == 2 || this.number == 3);
}

// get nice string telling text limit
CustomService.prototype.getLimitTranslation = function()
{
  if (this.number == 0) return new Translation("");
  
  var s;
  
  if (this.number == 1)
  {
    s = this.textLimit1.toString();
  }
  else if (this.number == 2)
  {
    s = this.textLimit2.toString();
  }
  else
  {
    s = this.textLimit1.toString() + " / " + this.textLimit2.toString();
  }
  
  var t = new Array();
  for (var i = 0; i < LanguagesCount; i++) 
  {
    t.push(MaxCharsTooltip.strings[i].replace(/\$\{n\}/, s)); 
  }
  
  return new Translation(t);
}

// put through the methods of the corresponding translation
CustomService.prototype.getString = function()
{
  return CustomServiceNames[this.number].getString();
}

CustomService.prototype.getInternalString = function()
{
  return CustomServiceNames[this.number].getInternalString();
}

CustomService.prototype.getHtmlString = function()
{
  return CustomServiceNames[this.number].getHtmlString();
}

CustomService.prototype.getHtmlStringWithAdd = function ()
{
  // returns all translation marked as <span class=... which will be handled by the js/css trickery
  var limitTranslation = this.getLimitTranslation();
  
  var translation = CustomServiceNames[this.number];
  
  translation.add = true;
  translation.addStrings = limitTranslation.strings;
  
  return translation.getHtmlStringWithAdd();
}