/**
 * @fileoverview Zapatec Auto Complete widget.
 *
 * <pre>
 * Copyright (c) 2004-2006 by Zapatec, Inc.
 * http://www.zapatec.com
 * 1700 MLK Way, Berkeley, California,
 * 94709, U.S.A.
 * All rights reserved.
 * </pre>
 */

/* $Id: zpautocomplete.js 5249 2006-11-21 21:24:39Z alex $ */

/**
 * Zapatec Auto Complete widget class. Extends base Zapatec Widget class
 * (utils/zpwidget.js).
 *
 * <pre>
 * <b>fields</b> [object] Array of input element objects or their ids.
 * AutoComplete object will be attached to all elements passed in this array and
 * shared among them. When one of input fields receives focus, AutoComplete
 * appears next to it. When field looses focus, AutoComplete disappears
 * automatically.
 *
 * Passing several elements gives ability to reuse the same AutoComplete object
 * among several input fields.
 *
 * If this option is not defined, initially AutoComplete object is not attached
 * to any input field. Later, after intialization it can be attached and
 * detached dynamically using {@link Zapatec.AutoComplete.addField} and
 * {@link Zapatec.AutoComplete.removeField} methods.
 *
 * <b>dataOnDemand</b> [boolean] Must be always true because currently this is
 * the only way for AutoComplete to get data. It makes sence to use this option
 * together with <b>callbackSource</b> config option defined in
 * {@link Zapatec.Widget} class. In this case AutoComplete passes to
 * <b>callbackSource</b> function following object:
 * {
 *   keyword: [string] entered 3 letter keyword
 * }
 * and lets it to form the source, e.g. server URL, from which tips are received
 * then.
 *
 * Currently AutoComplete accepts only JSON source. This means that
 * <b>callbackSource</b> must return either "json/url" or "json" sourceType.
 *
 * <b>convertTip</b> [function] Callback function that converts tips into
 * strings. Useful for complex tips. If not defined, tips are converted using
 * default conversion.
 *
 * <b>width</b> [string] CSS value of tips box width or "auto" to adjust it to
 * the field width. Default: content width.
 *
 * <b>height</b> [string] CSS value of tips box height. Default: content height.
 *
 * <b>overflow</b> [string] CSS value of tips box overflow. Default: "hidden".
 * </pre>
 *
 * @constructor
 * @extends Zapatec.Widget
 * @param {object} objArgs User configuration
 */
Zapatec.AutoComplete = function(objArgs) {
  // Call constructor of superclass
  Zapatec.AutoComplete.SUPERconstructor.call(this, objArgs);
};

// Inherit Widget
Zapatec.inherit(Zapatec.AutoComplete, Zapatec.Widget);

/**
 * Initializes object.
 *
 * @param {object} objArgs User configuration
 */
Zapatec.AutoComplete.prototype.init = function(objArgs) {
  // Call init method of superclass
  Zapatec.AutoComplete.SUPERclass.init.call(this, objArgs);
};

/**
 * Reconfigures the widget with new config options after it was initialized.
 * May be used to change look or behavior of the widget after it has loaded
 * the data. In the argument pass only values for changed config options.
 * There is no need to pass config options that were not changed.
 *
 * @param {object} objArgs Changes to user configuration
 */
Zapatec.AutoComplete.prototype.reconfigure = function(objArgs) {
  // Call parent method
  Zapatec.AutoComplete.SUPERclass.reconfigure.call(this, objArgs);
  // Redraw or do something else
  // ...
};

/**
 * Configures the widget. Gets called from init and reconfigure methods of
 * superclass.
 *
 * @private
 * @param {object} objArgs User configuration
 */
Zapatec.AutoComplete.prototype.configure = function(objArgs) {
  // Overwrite default config options if needed
  // Define new config options
  this.defineConfigOption('fields');
  this.defineConfigOption('dataOnDemand', false);
  this.defineConfigOption('convertTip');
  this.defineConfigOption('width');
  this.defineConfigOption('height');
  this.defineConfigOption('overflow', 'hidden');
  // Call parent method
  Zapatec.AutoComplete.SUPERclass.configure.call(this, objArgs);
  // Check passed config options and correct them if needed
  // By default dimensions are in pixels
  if (this.config.width && this.config.width == parseInt(this.config.width)) {
    this.config.width += 'px';
  }
  if (this.config.height && this.config.height == parseInt(this.config.height)) {
    this.config.height += 'px';
  }
  // Add fields
  if (this.config.fields instanceof Array) {
    for (var iField = 0; iField < this.config.fields.length; iField++) {
      this.addField(this.config.fields[iField]);
    }
  }
  // Current field
  this.field = null;
  // Currently selected tip
  this.tip = null;
  // Current set of tips
  this.data = null;
  // Tips cache
  this.cache = {};
};

/**
 * Attaches this AutoComplete object to the specified text field.
 *
 * @param {object} objField Input element object or id
 */
Zapatec.AutoComplete.prototype.addField = function(objField) {
  // Get field object
  objField = Zapatec.Widget.getElementById(objField);
  if (!objField || typeof objField.value == 'undefined') {
    return;
  }
  // Attach
  objField.zpAutoCompleteId = this.id;
  // Turn browser autocomplete feature off
  objField.setAttribute('autocomplete', 'off');
  // Add event listeners
  Zapatec.Utils.addEvent(objField, 'focus', Zapatec.AutoComplete.onFocus);
  Zapatec.Utils.addEvent(objField, 'keydown', Zapatec.AutoComplete.onKeyDown);
  Zapatec.Utils.addEvent(objField, 'keyup', Zapatec.AutoComplete.onKeyUp);
  Zapatec.Utils.addEvent(objField, 'blur', Zapatec.AutoComplete.onBlur);
};

/**
 * Detaches this AutoComplete object from the specified text field.
 *
 * @param {object} objField Input element object or id
 */
Zapatec.AutoComplete.prototype.removeField = function(objField) {
  // Get field object
  objField = Zapatec.Widget.getElementById(objField);
  if (!objField) {
    return;
  }
  // Detach
  var undef;
  objField.zpAutoCompleteId = undef;
  // Turn browser autocomplete feature on
  objField.removeAttribute('autocomplete');
  // Remove event listeners
  Zapatec.Utils.removeEvent(objField, 'focus', Zapatec.AutoComplete.onFocus);
  Zapatec.Utils.removeEvent(objField, 'keydown',Zapatec.AutoComplete.onKeyDown);
  Zapatec.Utils.removeEvent(objField, 'keyup', Zapatec.AutoComplete.onKeyUp);
  Zapatec.Utils.removeEvent(objField, 'blur', Zapatec.AutoComplete.onBlur);
};

/**
 * Field onfocus event listener.
 *
 * @private
 * @param {object} objEvent Event object
 */
Zapatec.AutoComplete.onFocus = function(objEvent) {
  // Get target element
  var objField = Zapatec.Utils.getTargetElement(objEvent);
  if (objField) {
    // Call method of attached AutoComplete object
    Zapatec.Widget.callMethod(objField.zpAutoCompleteId, 'onFocus', objField);
  }
};

/**
 * Switches AutoComplete to the specified field when it is focused. Field must
 * be previously added using Zapatec.AutoComplete#addField method.
 *
 * @private
 * @param {object} objField Input field element object
 */
Zapatec.AutoComplete.prototype.onFocus = function(objField) {
  // Unset current field
  this.field = null;
  // Field must be previously attached
  if (!objField || objField.zpAutoCompleteId != this.id) {
    return;
  }
  // Set current field
  this.field = objField;
};

/**
 * Field onblur event listener.
 *
 * @private
 * @param {object} objEvent Event object
 */
Zapatec.AutoComplete.onBlur = function(objEvent) {
  // Get target element
  var objField = Zapatec.Utils.getTargetElement(objEvent);
  if (objField) {
    // Call method of attached AutoComplete object
    Zapatec.Widget.callMethod(objField.zpAutoCompleteId, 'onBlur');
  }
};

/**
 * Selects first tip and hides tips on field blur.
 * @private
 */
Zapatec.AutoComplete.prototype.onBlur = function() {
  // Do nothing if tip was selected
  if (!this.tip) {
    // Select first tip
    this.selectTip(0);
  }
};

/**
 * Field onkeydown event listener.
 *
 * @private
 * @param {object} objEvent Event object
 */
Zapatec.AutoComplete.onKeyDown = function(objEvent) {
  // Get target element
  var objField = Zapatec.Utils.getTargetElement(objEvent);
  if (objField) {
    // Call method of attached AutoComplete object
    Zapatec.Widget.callMethod(objField.zpAutoCompleteId, 'onKeyDown', objEvent);
  }
};

/**
 * Hides tips on Esc.
 *
 * @private
 * @param {object} objEvent Event object
 */
Zapatec.AutoComplete.prototype.onKeyDown = function(objEvent) {
  // Get event object in IE
  if (!objEvent) {
    objEvent = window.event;
  }
  // Hide tips on Esc
  if (objEvent.keyCode == 27) {
    this.hide();
    // Prevent entered value from erasing
    Zapatec.Utils.stopEvent();
  }
};

/**
 * Field onkeyup event listener.
 *
 * @private
 * @param {object} objEvent Event object
 */
Zapatec.AutoComplete.onKeyUp = function(objEvent) {
  // Get target element
  var objField = Zapatec.Utils.getTargetElement(objEvent);
  if (objField) {
    // Call method of attached AutoComplete object
    Zapatec.Widget.callMethod(objField.zpAutoCompleteId, 'onKeyUp', objEvent);
  }
};

/**
 * Shows tips when there are at least 3 chars entered in the field.
 *
 * @private
 * @param {object} objEvent Event object
 */
Zapatec.AutoComplete.prototype.onKeyUp = function(objEvent) {
  // Get event object in IE
  if (!objEvent) {
    objEvent = window.event;
  }
  // Hide tips on Esc
  if (objEvent.keyCode == 27) {
    return;
  }
  // Field must be attached
  if (!this.field) {
    return;
  }
  if (this.field.value.length > 2) {
    // Load data from server
    this.loadData();
  } else if (!this.field.value.length) {
    // Hide tips
    this.hide();
  }
};

/**
 * Reloads data from the specified source after widget is initialized. Argument
 * should be passed only when dataOnDemand config option is true and
 * callbackSource config option is defined. See description of dataOnDemand
 * config option for details.
 *
 * @param {object} objArgs (Optional) Arguments object
 */
Zapatec.AutoComplete.prototype.loadData = function(objArgs) {
  // Form arguments object
  if (this.config.dataOnDemand) {
    if (typeof objArgs != 'object') {
      objArgs = {};
    }
    objArgs.keyword = this.field.value;
  }
  // Call parent method
  Zapatec.AutoComplete.SUPERclass.loadData.call(this, objArgs);
};

/**
 * Loads data from the JSON source.
 *
 * @private
 * @param {object} objData Input data object
 */
Zapatec.AutoComplete.prototype.loadDataJson = function(objData) {
  // Get data
  if (!(objData instanceof Object)) {
    objData = {};
  }
  if (!(objData.tips instanceof Array)) {
    objData.tips = [];
  }
  this.data = objData;
  // Show tips
  this.show();
};

/**
 * Shows box with tips.
 * @private
 */
Zapatec.AutoComplete.prototype.show = function() {
  // Hide old tips
  this.hide();
  // Check if there are data
  if (!this.data || !(this.data.tips instanceof Array) ||
   !this.data.tips.length) {
    return;
  }
  // Check if field is attached
  if (!this.field || !this.field.parentNode) {
    return;
  }
  // Remove currently selected tip
  this.tip = null;
  // Create container and WCH
  if (!this.container) {
    // Create container
    this.container = Zapatec.Utils.createElement('div');
    this.container.style.position = 'absolute';
    this.container.style.display = 'none';
    // Insert container
    this.field.parentNode.insertBefore(this.container, this.field);
    // Correct container position
    this.container.style.top = (Zapatec.Utils.getElementOffset(this.field).top + this.field.offsetHeight) + 'px';
    // Create WCH
    this.wch = Zapatec.Utils.createWCH(this.container);
    // Put WCH under container
    if (this.wch) {
      this.wch.style.zIndex = -1;
    }
    // Create content
    this.content = Zapatec.Utils.createElement('div', this.container);
    this.content.className = this.getClassName({prefix: 'zpAutoComplete'});
    // Setup dimensions
    if (this.config.width) {
      if (this.config.width == 'auto') {
        this.content.style.width = this.field.offsetWidth + 'px';
      } else {
        this.content.style.width = this.config.width;
      }
    }
    if (this.config.height) {
      this.content.style.height = this.config.height;
    }
    this.content.style.overflow = this.config.overflow;
  } else if (this.container.parentNode != this.field.parentNode) {
    // Move container
    this.field.parentNode.insertBefore(this.container, this.field);
    // Correct container position
    this.container.style.top = (Zapatec.Utils.getElementOffset(this.field).top + this.field.offsetHeight) + 'px';
  }
  // Add tips
  for (var iTip = 0; iTip < this.data.tips.length; iTip++) {
    var objTip = this.data.tips[iTip];
    var arrHtml = [];
    arrHtml.push('<div onmousedown="Zapatec.Widget.callMethod(\'');
    arrHtml.push(this.id);
    arrHtml.push("','selectTip',");
    arrHtml.push(iTip);
    arrHtml.push(')">');
    
    document.getElementById('debbuger').innerHTML += '<hr>&lt;div onmousedown="Zapatec.Widget.callMethod(\''+this.id+"','selectTip',"+iTip+')"&gt;';
    
    if (typeof this.config.convertTip == 'function') {
      arrHtml.push(this.config.convertTip(objTip));
    } else {
      // Convert to string by default
      arrHtml.push(objTip + '');
    }
    arrHtml.push('</div>');
    this.content.innerHTML += arrHtml.join('');
  }
  // Show container
  this.container.style.display = '';
  // Setup WCH
  Zapatec.Utils.setupWCH(this.wch, 0, 0, this.container.offsetWidth, this.container.offsetHeight);
};

/**
 * Hides box with tips.
 * @private
 */
Zapatec.AutoComplete.prototype.hide = function() {
  if (this.container) {
    // Hide container
    this.container.style.display = 'none';
    // Remove tips
    this.content.innerHTML = '';
  }
};

/**
 * Selects one of visible tips.
 *
 * @private
 * @param {number} iTip Index of tip to select in the visible tips array
 */
Zapatec.AutoComplete.prototype.selectTip = function(iTip) {
  // Hide tips
  this.hide();
  // Get tip
  if (!this.data || !(this.data.tips instanceof Array) || typeof this.data.tips[iTip] == 'undefined') {
    return;
  }
  var objTip = this.data.tips[iTip];
  // Select tip
  this.tip = objTip;
  // Update field
  if (typeof this.config.convertTip == 'function') {
    // Convert value using callback
    this.field.value = this.config.convertTip(objTip);
	document.getElementById('debbuger').innerHTML += '<hr>IF - '+this.config.convertTip(objTip);
	detailsProductCode(this.config.convertTip(objTip));
	
	
  } else if (this.field) {
    // Convert to string
    this.field.value = objTip + '';
  }
};

Zapatec.Utils.addEvent(window, 'load', Zapatec.Utils.checkActivation);
