function PersonalizationProfile(profileId, flashObj, numLines, charsPerLine, upchargeCents, allCaps, displayName, flashBasedForm, profileAttributes, swfURL, swfWidth, swfHeight, requirePersonalization, initialSelection)
{
  this.profileId = profileId;
  this.flashObj = flashObj;
  this.numLines = numLines;
  this.charsPerLine = charsPerLine;
  this.upchargeCents = upchargeCents;
  this.allCaps = allCaps;
  this.displayName = displayName;
  this.flashBasedForm = flashBasedForm;
  this.profileAttributes = profileAttributes;
  this.swfURL = swfURL;
  this.swfWidth = swfWidth;
  this.swfHeight = swfHeight;
  this.setVariableQueue = new Object();
  this.setVariableQueueBusy = false;
  this.requirePersonalization = requirePersonalization;
  this.initialSelection = initialSelection;
  
  this.profileAttributeFlashValues = new Array(this.profileAttributes.length);
  this.lineFlashValues = new Array(this.numLines);
}

PersonalizationProfile.prototype.ENUMERATION_NAMES = ['first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'eight', 'nineth', 'tenth'];

PersonalizationProfile.prototype.getMaximumCharsPerLine = function()
{
  var n = 0;
  for (var i = 0; i < this.charsPerLine.length; i++)
    if (this.charsPerLine[i] > n)
      n = this.charsPerLine[i];
  return n;
}

PersonalizationProfile.prototype.requestSetVariable = function(varName, varValue)
{
  this.setVariableQueue['queue' + varName] = varValue;
  if (!this.setVariableQueue.isBusy)
    this.processSetVariableQueue();
  return;
}

PersonalizationProfile.prototype.getFlashObj = function()
{
  if (this.flashObj != null)
    return this.flashObj;
  var t = document[this.getDomName('Personalization')];
  if (t[1])
    return t[1];
  return t;
}

PersonalizationProfile.prototype.processSetVariableQueue = function()
{
  this.setVariableQueueBusy = true;
  var hadFailures = false;
  if (this.getFlashObj())
  {
    for (var key in this.setVariableQueue)
    {
      if ((key.length > 5) && (key.substring(0, 5) == 'queue'))
      {
        try
        {
          this.getFlashObj().SetVariable(key.substring(5, key.length), this.setVariableQueue[key]);
          delete this.setVariableQueue[key];
        }
        catch (e)
        {
          hadFailures = true;
        }
      }
    }
  }
  else
    hadFailures = true;
  if (hadFailures)
    window.setTimeout(this.subcatObj.jsName + '.personalizationProfile.processSetVariableQueue()', 500);
  this.setVariableQueueBusy = false;
  return;
}

PersonalizationProfile.prototype.createLinesMessage = function(charsPerLine)
{
  var charsPerLineValues = [];
outerLoop:
  for (var i = 0; i < charsPerLine.length; i++)
  {
    for (var j = 0; j < charsPerLineValues.length; j += 2)
    {
      if (charsPerLine[i] == charsPerLineValues[j])
      {
        var indexList = charsPerLineValues[j + 1];
        indexList.push(i);
        continue outerLoop;
      }
    }
    charsPerLineValues.push(charsPerLine[i]);
    charsPerLineValues.push([i]);
  }
  if (charsPerLineValues.length == 0)
    return '';
  if (charsPerLineValues.length == 2)
    return '' + charsPerLineValues[0] + ' characters per line (including spaces)';
  var t = '';
  for (var i = 0; i < charsPerLineValues.length; i += 2)
  {
    var cpl = charsPerLineValues[i];
    var lineNumbers = charsPerLineValues[i + 1];
    t += cpl + ' characters per line for the';
    for (var j = 0; j < lineNumbers.length; j++)
    {
      if (j == 0)
        t += ' ';
      else
      {
        if ((j + 1) == lineNumbers.length)
        {
          if (j == 1)
            t += ' and ';
          else
            t += ', and ';
        }
        else
          t += ', ';
      }
      t += this.ENUMERATION_NAMES[lineNumbers[j]];
    }
    t += (lineNumbers.length == 1) ? ' line; ' : ' lines; ';
  }
  t += 'spaces included';
  return t;
}

PersonalizationProfile.prototype.createMessage = function()
{
  var msg = this.createLinesMessage(charsPerLine);
  if (this.upchargeCents > 0)
  {
    if (msg.length > 0)
      msg += '<br>\n';
    msg += 'Upcharge for this service is <u>' + formatPriceWithSign(this.upchargeCents) + '</u>';
  }
  return msg;
}


PersonalizationProfile.prototype.keyPressHandler = function(lineNumber, inputObj)
{
  if (lineNumber >= this.numLines)
    return;
  if (this.allCaps)
    inputObj.value = inputObj.value.toUpperCase();
  this.requestSetVariable('message' + (lineNumber + 1), inputObj.value);
  return;
}

PersonalizationProfile.prototype.attrSelectionHandler = function(attributeIndex, selObj)
{
  if (attributeIndex >= this.profileAttributes.length)
    return;
  var si = selObj.selectedIndex;
  if (si < 0)
    return;
  this.requestSetVariable(this.profileAttributes[attributeIndex].variableName, selObj.options[si].text.toUpperCase());
  return;
}

PersonalizationProfile.prototype.getAttributeIndexByVarName = function(attrName)
{
  for (var i = 0; i < this.profileAttributes.length; i++)
    if (this.profileAttributes[i].variableName == attrName)
      return i;
  return -1;
}

PersonalizationProfile.prototype.getAttributeIndexById = function(attributeId)
{
  for (var i = 0; i < this.profileAttributes.length; i++)
    if (this.profileAttributes[i].attributeId == attributeId)
      return i;
  return -1;
}

PersonalizationProfile.prototype.getDomName = function(name)
{
  if (this.subcatObj)
    return this.subcatObj.getDomName(name);
  return name;
}

PersonalizationProfile.prototype.getForm = function()
{
  return document.forms[this.getDomName('PersonalizationForm')];
}

PersonalizationProfile.prototype.getSelectList = function(f, attrIndex)
{
  if (f)
    return f[this.getDomName('PersonalizationSel' + attrIndex)];
  return null;
}

PersonalizationProfile.prototype.getInputBox = function(f, lineNumber)
{
  if (f)
    return f[this.getDomName('PersonalizationLine' + lineNumber)];
  return null;
}

PersonalizationProfile.prototype.setLineContent = function(lineNumber, lineContent, signalChange)
{
  var inputBox = this.getInputBox(this.getForm(), lineNumber);
  if (inputBox)
    inputBox.value = lineContent;
  if (signalChange)
    this.keyPressHandler(lineNumber, inputBox);
  return;
}

PersonalizationProfile.prototype.setSelectionById = function(selIndex, valueId, signalChange)
{
  var s = this.getSelectList(this.getForm(), selIndex);
  if (s)
  {
    valueId = '' + valueId;
    for (var i = 0; i < s.options.length; i++)
    {
      if (s.options[i].value == valueId)
      {
        this.setSelectionByIndex(selIndex, i, signalChange);
        return;
      }
    }
  }
  return;
}

PersonalizationProfile.prototype.setSelectionByText = function(selIndex, valueText, signalChange)
{
  var s = this.getSelectList(this.getForm(), selIndex);
  if (s)
  {
    valueText = removeBadIdChars(valueText).toLowerCase();
    for (var i = 0; i < s.options.length; i++)
    {
      if (removeBadIdChars(s.options[i].text).toLowerCase() == valueText)
      {
        this.setSelectionByIndex(selIndex, i, signalChange);
        return;
      }
    }
  }
  return;
}


PersonalizationProfile.prototype.setSelectionByIndex = function(selIndex, valueIndex, signalChange)
{
  var s = this.getSelectList(this.getForm(), selIndex);
  if (s)
  {
    if (valueIndex >= 0)
    {
      s.selectedIndex = valueIndex;
      if (signalChange)
        this.attrSelectionHandler(selIndex, s);
    }
  }
  return;
}

PersonalizationProfile.prototype.init = function()
{
  var f = this.getForm();
  if (f)
  {
    for (var i = 0; i < this.profileAttributes.length; i++)
    {
      var s = this.getSelectList(f, i);
      if (s)
        this.attrSelectionHandler(i, s);
    }
    for (var i = 0; i < this.numLines; i++)
    {
      var t = this.getInputBox(f, i);
      if (t)
      {
        if ((this.initialSelection != null) && (this.initialSelection.selectionLines.length > i))
          t.value = this.initialSelection.selectionLines[i];
        this.keyPressHandler(i, t);
      }
    }
  }
  return;
}

PersonalizationProfile.prototype.receiveFSCommand = function(command, args)
{
  var attrIndex = this.getAttributeIndexByVarName(command);
  if (attrIndex >= 0)
  {
    var f = this.getForm();
    var s = this.getSelectList(f, attrIndex);
    if (s == null)
    {
      var attr = this.profileAttributes[attrIndex];
      for (var i = 0; i < attr.values.length; i++)
      {
        if (removeBadIdChars(attr.values[i].valueText).toLowerCase() == args)
        {
          this.profileAttributeFlashValues[attrIndex] = attr.values[i].valueId;
          return;
        }
      }
      return;
    }
    for (var i = 0; i < s.options.length; i++)
    {
      if (removeBadIdChars(s.options[i].text).toLowerCase() == args)
      {
        s.selectedIndex = i;
        return;
      }
    }
    // Not found!
    return;
  }
  if ((command.length < 8) || (command.substring(0, 7) != 'message'))
  {
    // Unknown!
    return;
  }
  var n = parseInt(command.substring(7, command.length));
  if ((n <= 0) || (n > this.numLines))
  {
    // Line number out of range
    return;
  }
  var inpBox = this.getInputBox(f, n - 1);
  if (inpBox == null)
    this.lineFlashValues[n - 1] = args;
  else
    inpBox.value = args;
  return;
}

PersonalizationProfile.prototype.getHtml = function()
{
  var t = '<form name="' + this.subcatObj.getDomName('PersonalizationForm') + '" style="margin: 0">\n' +
          '  <table class="productform" border="0" cellspacing="0" cellpadding="2">\n' +
          '    <tr>\n' +
          '      <td bgcolor="#000000" colspan=2 class="productform"><font color="#FFFFFF"><b>' + this.displayName + '</b></font></td>\n' +
          '    </tr>\n';
  for (var i = 0; i < this.profileAttributes.length; i++)
  {
    var profileAttribute = this.profileAttributes[i];
    t += '    <tr>\n' +
         '      <td bgcolor="#F8F8F8" class="smalltext">' + profileAttribute.getDisplayName() + ':</td>\n' +
         '      <td bgcolor="#F8F8F8">\n' +
         '        <select name="' + this.subcatObj.getDomName('PersonalizationSel' + i) + '" class="smalltext" onChange="' + this.subcatObj.jsName + '.personalizationProfile.attrSelectionHandler(' + i + ', this)">\n';
    var defaultValueId = profileAttribute.defaultValueId;
    if (this.initialSelection != null)
    {
      var selectedValueId = this.initialSelection.getAttributeValueIdById(profileAttribute.attributeId);
      if (selectedValueId > 0)
        defaultValueId = selectedValueId;
    }
    for (var j = 0; j < profileAttribute.values.length; j++)
    {
      var pav = profileAttribute.values[j];
      t += '          <option value="' + pav.valueId + '"';
      if (defaultValueId == pav.valueId)
        t += ' SELECTED';
      t += '>' + pav.valueText + '</option>\n';
    }
    t += '        </select>\n' +
         '      </td>\n' +
         '    </tr>\n';
  }
  
  if (this.numLines > 0)
  {
    t += '    <tr>\n' +
         '      <td valign="top" bgcolor="#F8F8F8" class="smalltext">Message:</td>\n' +
         '      <td bgcolor="#F8F8F8">\n';
    for (var i = 0; i < this.numLines; i++)
    {
      if (i > 0)
        t += '<br>\n';

      t += '        <input type="text" name="' + this.subcatObj.getDomName('PersonalizationLine' + i) + '" size=10 maxlength=' + this.getMaximumCharsPerLine() + ' class="smalltext"\n' +
                      ' onKeyPress="' + this.subcatObj.jsName + '.personalizationProfile.keyPressHandler(' + i + ', this)"\n' +
                      ' onKeyUp="' + this.subcatObj.jsName + '.personalizationProfile.keyPressHandler(' + i + ', this)"\n' +
                      ' onChange="' + this.subcatObj.jsName + '.personalizationProfile.keyPressHandler(' + i + ', this)">\n';
    }
    t += '      </td>\n' +
         '    </tr>\n';
  }
  t += '  </table>\n' +
       '</form>';
  return t;
}

PersonalizationProfile.prototype.display = function()
{
  var d = document.getElementById(this.subcatObj.getDomName('PersonalizationDiv'));
  if (d)
  {
    d.innerHTML = this.getHtml();
    this.init();
  }
  return;
}

PersonalizationProfile.prototype.getSelection = function()
{
  var vals = [];
  for (var i = 0; i < this.profileAttributes.length; i++)
  {
    var s = this.getSelectList(this.getForm(), i);
    if (s == null)
    {
      if (this.profileAttributeFlashValues[i] != null)
      {
        var valueId = parseInt(this.profileAttributeFlashValues[i]);
        if (valueId > 0)
        {
          vals.push(this.profileAttributes[i].attributeId);
          vals.push(valueId);
          continue;
        }
      }
      if (this.profileAttributes[i].defaultValueId > 0)
      {
        vals.push(this.profileAttributes[i].attributeId);
        vals.push(this.profileAttributes[i].defaultValueId);
        continue;
      }
      continue;
    }
    var si = s.selectedIndex;
    if (si >= 0)
    {
      var valueId = parseInt(s.options[si].value);
      if (valueId > 0)
      {
        vals.push(this.profileAttributes[i].attributeId);
        vals.push(valueId);
      }
    }
  }
  
  var lines = [];
  for (var i = 0; i < this.numLines; i++)
  {
    var lineBox = this.getInputBox(this.getForm(), i);
    var lineValue = (lineBox == null) ? this.lineFlashValues[i] : lineBox.value;
    if (lineValue == null)
      lineValue = '';
    if (this.allCaps)
      lineValue = lineValue.toUpperCase();
    if (lineValue.length > this.charsPerLine[i])
      lineValue = lineValue.substring(0, this.charsPerLine[i]);
    lines.push(lineValue);
  }
  return new PersonalizationSelection(this.profileId, vals, lines);
}

PersonalizationProfile.prototype.getSelectionSerialized = function()
{
  var sel = this.getSelection();
  return sel.getSerializedData();
}

PersonalizationProfile.prototype.createFlashObject = function()
{
  var personalizationDomName = this.subcatObj.getDomName('Personalization')
  var newArgs = [this.subcatObj.getDomName('PersonalizationFlashDiv'),
    'allowScriptAccess','sameDomain',
    'movie', this.swfURL,
    'name', personalizationDomName,
    'id', personalizationDomName,
    'quality', 'high',
    'bgcolor', '#ffffff',
    'wmode', 'transparent',
    'swliveconnect', 'true',
    'codebase', 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0',
    'pluginspage', 'http://www.macromedia.com/go/getflashplayer',
    'width', '' + this.swfWidth,
    'height', '' + this.swfHeight,
    'src', this.swfURL
  ];
  createFlashObjectWithHooks(this.subcatObj.getDomName('PersonalizationFlashDiv'), newArgs, personalizationDomName, this.subcatObj.jsName + '.personalizationProfile');
  return;
}

/* ****************************** PersonalizationProfileAttribute ****************************** */

function PersonalizationProfileAttribute(profileAttributeId, attributeId, attributeName, displayName, variableName, defaultValueId, valueData)
{
  this.profileAttributeId = profileAttributeId;
  this.attributeId = attributeId;
  this.attributeName = attributeName;
  this.displayName = displayName;
  this.variableName = variableName;
  this.defaultValueId = defaultValueId;
  this.values = new Array();
  for (var i = 0; i < valueData.length; i += 2)
    this.values[this.values.length] = new PersonalizationProfileAttributeValue(valueData[i], valueData[i + 1]);
}

PersonalizationProfileAttribute.prototype.getValueIndexById = function(valueId)
{
  for (var i = 0; i < this.values.length; i++)
    if (this.values[i].valueId == valueId)
      return i;
  return -1;
}

PersonalizationProfileAttribute.prototype.getValueById = function(valueId)
{
  var ind = this.getValueIndexById(valueId);
  if (ind < 0)
    return null;
  return this.values[ind];
}

PersonalizationProfileAttribute.prototype.getValueTextById = function(valueId)
{
  var v = this.getValueById(valueId);
  if (v == null)
    return null;
  return v.valueText;
}

PersonalizationProfileAttribute.prototype.getDisplayName = function()
{
  if (this.displayName.length > 0)
    return this.displayName;
  return this.attributeName;
}

/* ****************************** PersonalizationProfileAttributeValue ****************************** */

function PersonalizationProfileAttributeValue(valueId, valueText)
{
  this.valueId = valueId;
  this.valueText = valueText;
}

/* ****************************** PersonalizationSelection ****************************** */

function PersonalizationSelection(profileId, selectionValues, selectionLines)
{
  this.profileId = profileId;
  this.selectionLines = selectionLines;
  this.selectionValues = selectionValues;
}

PersonalizationSelection.prototype.getSerializedData = function()
{
  var t = '' + (this.selectionValues.length >>> 1) + ',' + this.selectionLines.length;
  for (var i = 1; i < this.selectionValues.length; i += 2)
    t += ',' + escape(this.selectionValues[i - 1]) + ',' + escape(this.selectionValues[i]);
  for (var i = 0; i < this.selectionLines.length; i++)
    t += ',' + escape(this.selectionLines[i]);
  return t;
}

PersonalizationSelection.prototype.getNumSelectionValues = function()
{
  return (this.selectionValues.length >>> 1);
}

PersonalizationSelection.prototype.getAttributeIndexById = function(attributeId)
{
  for (var i = 1; i < this.selectionValues.length; i += 2)
    if (this.selectionValues[i - 1] == attributeId)
      return (i >>> 1);
  return -1;
}

PersonalizationSelection.prototype.getAttributeValueIdById = function(attributeId)
{
  var attributeIndex = this.getAttributeIndexById(attributeId);
  if (attributeIndex < 0)
    return -1;
  return this.getAttributeValueIdFromIndex(attributeIndex);
}

PersonalizationSelection.prototype.getAttributeIdFromIndex = function(attributeIndex)
{
  if (attributeIndex < 0)
    return -1;
  return this.selectionValues[attributeIndex << 1];
}

PersonalizationSelection.prototype.getAttributeValueIdFromIndex = function(attributeIndex)
{
  if (attributeIndex < 0)
    return -1;
  return this.selectionValues[(attributeIndex << 1) + 1];
}

