//
// EXAMPLE ACCESS:
//
// function createNewCategoryListing(startingSequence) {
//   eval('catList' + categoryListings + '= new RecursiveListing(categoryListings, \'catList' + categoryListings + '\')');
//   eval('catList' + categoryListings + '.contentArray = "categoryArray"');
//   if (startingSequence != null) eval('catList' + categoryListings + '.startingSequence = "'+ startingSequence+ '"');
//   eval('catList' + categoryListings + '.start()');
//   categoryListings++;
// }
//

function RecursiveListing(unique_num, instance_name) {

  // required variables (defined as arguments)
  this.unique           = (unique_num != null) ? unique_num : '0';      // a unique number (to define pulldown ids)
  this.instanceName     = (instance_name != null) ? instance_name : ''; // the name of the variable that holds the instance

  // required variables (these shouldn't need to be changed)
  this.categoryChildren = 'categoryChildren';  // category --> child array  (note, string as to not load array twice (big!))
  this.categoryParents  = 'categoryParents';   // category --> parent array (note, string as to not load array twice (big!))

  // optional variables (defined as 'objectName.variableName = value')
  this.startingCat      = 0;           // INT, starting category number
  this.beginAt          = 0;           // INT, a value representing the PK off the root to start at
  this.dontShow         = new Array;   // ARRAY, don't show these categories
  this.canAddNew        = true;        // BOOL, whether or not "-- add new subcategory" is provided
  this.defRootOption    = "-- Please select a category";
  this.defSubOption     = "-- Continue to a subcategory?";
  this.defAddOption     = "-- Add a new subcategory";
  this.defRemoveOption  = "-- Remove";
  this.parentDivId      = "categories";
  this.selectClass      = "categories";
  this.divClass         = "categoryDiv";
  this.selectIdPrefix   = "category_id";
  this.divIdPrefix      = "category_div";

  // local variables
  this.selects          = new Array;   // formats as: { num => select_id }

  // methods
  this.returnKey        = returnKey;
  this.start            = start;
  this.is_valid_list    = is_valid_list;
  this.returnChildren   = returnChildren;
  this.returnParent     = returnParent;
  this.returnParentList = returnParentList;
  this.clearSubs        = clearSubs;
  this.returnSelectNum  = returnSelectNum;
  this.returnLastValue  = returnLastValue;
  this.selectOnChange   = selectOnChange;
  this.addNewSub        = addNewSub;
  this.addSub           = addSub;

  function returnKey(myArr, myVal) {
    for (var myKey in myArr) {
      if (myArr[myKey] == myVal) {
        return myKey;
      }
    }
    return false;
  }

  function start() {
    if (this.startingCat.length > 0) {
      var addSubArray = this.returnParentList(this.startingCat);
      if (!this.is_valid_list(addSubArray)) return false;
      for (var j = 0; j < this.dontShow.length; j++) {
        if (in_array(addSubArray, this.dontShow[j])) return false;
      }
      for (var j = 0; j < addSubArray.length; j++) {
        if (addSubArray[j] == this.beginAt) continue;
        this.addSub(addSubArray[j]);
      }
    }
    this.addSub();
    return true;
  }

  function is_valid_list(addSubArray) {
    // TODO: this might cause problems down the road
    // it assume this.beginAt must always be a root category
    if (this.beginAt > 0 && addSubArray[0] != this.beginAt) return false;
    return true;
  }

  function returnChildren(catId) {
    var children = new Array;
    if (!window[this.categoryChildren][catId]) return false;
    for (var j = 0; j < window[this.categoryChildren][catId].length; j++) {
      children[j] = window[this.categoryChildren][catId][j];
    }
    return children;
  }

  function returnParent(catId) {
    return window[this.categoryParents][catId];
  }

  function returnParentList(catId) {
    var returnList = new Array;
    var k = 0;
    returnList[k] = catId;
    k++;
    var parent_id = this.returnParent(catId);
    if (parent_id > 0) {
      returnList[k] = parent_id;
      k++;
      var j = 1;
      while (parent_id > 0 && j < 100) {
        parent_id = this.returnParent(parent_id);
        if (parent_id > 0) returnList[k] = parent_id;
        k++;
        j++;
      }
    }
    return returnList.reverse();
  }

  function clearSubs(afterIndex) {

    afterIndex = parseFloat(afterIndex);

    // remove from select array
    this.selects.splice((afterIndex+1), (this.selects.length - afterIndex));

    // remove physical select elements
    afterIndex++;
    var searchFor = $(this.selectIdPrefix+'_'+this.unique+'_'+afterIndex);
    while (searchFor) {
      searchFor.parentNode.removeChild(searchFor);
      afterIndex++;
      searchFor = $(this.selectIdPrefix+'_'+this.unique+'_'+afterIndex);
    }

    // remove new text box (if exists)
    var newBox = $(this.selectIdPrefix+'_'+this.unique+'_new');
    if (newBox) newBox.parentNode.removeChild(newBox);
    var newBox = $(this.selectIdPrefix+'_'+this.unique+'_newButton');
    if (newBox) newBox.parentNode.removeChild(newBox);

  } // end clearSubs()

  function returnSelectNum(select_id) {
    for (num in this.selects) {
      if (this.selects[num] == select_id) return num;
    }
    return false;
  }

  function returnLastValue() {
    var lastValue = 0;
    for (var x in this.selects) {
      var selectObj = $(this.selects[x]);
      var myVal = selectObj.options[selectObj.selectedIndex].value;
      var myText = selectObj.options[selectObj.selectedIndex].text;
      if (myText != this.defRootOption && myText != this.defSubOption && myText != this.defAddOption && myText != this.defRemoveOption) {
        lastValue = myVal;
      }
    }
    return lastValue;
  }

  function selectOnChange(selectObj) {

    if (currentIndex = this.returnSelectNum(selectObj.id)) {

      // always clear out sub pulldowns..
      // an onchange means the sub cats will always be different
      this.clearSubs(currentIndex);

      var pulldown_id = this.selectIdPrefix+'_'+this.unique+'_'+currentIndex;
      if ($(pulldown_id).options[$(pulldown_id).selectedIndex].text == this.defAddOption) {
        // user wants to add a new subcategory
        this.addNewSub($(pulldown_id));
        return;
      }

      // this.defRemoveOption (eg "-- Remove") is selected
      if (selectObj.options[selectObj.selectedIndex].text.indexOf(this.defRemoveOption) != -1) {
        selectObj.parentNode.removeChild(selectObj);
        this.selects.splice((this.selects.length-1), 1);
      }

      // this.defRootOption (eg "-- Please select ...") is selected
      if (selectObj.options[selectObj.selectedIndex].text.indexOf(this.defRootOption) != -1) {
        return;
      }

      // this.defSubOption (eg "-- Please select a sub ...") is selected
      if (selectObj.options[selectObj.selectedIndex].text.indexOf(this.defSubOption) != -1) {
        return;
      }

      this.addSub();

      // attempt to blur the current select box (this is something Craig likes to do...)
      try {
        selectObj.blur();
      } catch(e) {}

      // TODO: this is hard-coded
      if (this.categoryChildren.indexOf('category') != -1 && window.showArtForm) showArtForm();

    } else {
      alert('There was an error attempting to administer categories.  Please try again.');
    }

  } // end selectOnChange()

  function addNewSub(lastObj) {

    var myVar = this.selectIdPrefix+'_'+this.unique+'_new';
    var myLast = this.returnLastValue();

    var theForm = document.createElement("FORM");
    theForm.setAttribute("method", "post");
    theForm.setAttribute("action", "");
    theForm.setAttribute("style", "margin:0px 0px 0px 0px;");
    theForm.id = this.selectIdPrefix+'_'+this.unique+'_newForm';
    theForm.onsubmit = function() { if ($(myVar).value != '<Name of new subcategory>') ajaxNewSub(myVar, myLast); return false }

    var theElement = document.createElement("INPUT");
    theElement.setAttribute("type", "text");
    theElement.id   = this.selectIdPrefix+'_'+this.unique+'_new';
    theElement.name = this.selectIdPrefix+'_'+this.unique+'_new';
    theElement.style.width = '226px';
    theElement.value = '<Name of new subcategory>';
    theElement.onclick = function () { clearDefaultValue(this,'<Name of new subcategory>') }
    theForm.appendChild(theElement);

    var theElement = document.createElement("INPUT");
    theElement.setAttribute("type", "button");
    theElement.id = this.selectIdPrefix+'_'+this.unique+'_newButton';
    theElement.className = 'hollow';
    theElement.style.marginLeft='4px';
    theElement.onclick = function () { if ($(myVar).value != '<Name of new subcategory>') ajaxNewSub(myVar, myLast); }
    theElement.value = 'Save';
    theForm.appendChild(theElement);

    lastObj.parentNode.appendChild(theForm);

  }

  function addSub(defaultSelectedValue) {

    var current_num = this.selects.length;

    // create the select pulldown
    var theSelect = document.createElement("SELECT");
        theSelect.className = this.selectClass;
        theSelect.id   = this.selectIdPrefix+'_'+this.unique+'_'+current_num;
        theSelect.name = this.selectIdPrefix+'_'+this.unique+'_'+current_num;
        var objName = this.instanceName;
        theSelect.onchange =  function () { window[objName].selectOnChange(this); }

    // add first option (eg "-- Please select ...")
    var theOption;
    var optionText = (current_num == 0) ? this.defRootOption : this.defSubOption;
        theOption = new Option(optionText,0);
        theSelect.options[0] = theOption;
        theSelect.selectedIndex = 0;

    // determine parent pk value
    if (current_num > 0) {
      var parent_num = current_num - 1;
      var parent_select = $(this.selects[parent_num]);
      var parent_value  = parent_select.options[parent_select.selectedIndex].value;
    } else {
      if (this.beginAt  > 0) {
        var parent_value = parseFloat(this.beginAt);
      } else {
        var parent_value = 0;
      }
    }

    var k = 1;  // ALERT: preserve for the next for if statements

    // add second option (eg, "-- Add a subcategory?")
    if (this.canAddNew && parent_value > 0 && this.beginAt != parent_value) {
      var theOption;
          theOption = new Option(this.defAddOption,0);
          theSelect.options[k] = theOption;
          k++;
    }

    // add options from database (list of categories)

    // TOOD: this is a true WTF... we didn't catch this until after release,
    // so having to work around in javascript to avoid changes to more core system code
    // In safari, the order of the array is not preserved (it is re-ordered based on key).
    // [so, the real WTF is that I didn't aniticipate this happening...]
    // this is the workaround...
    var isSafari = (navigator.vendor) ? true : false;
    var sortedArray = new Array;
    var myKey
    // setting an array = to another array creates a pointer to the first array.  Workaround....
    for (myKey in window[this.categoryChildren][parent_value]) {
      sortedArray[myKey] = window[this.categoryChildren][parent_value][myKey];
    }
    if (isSafari) sortedArray.sort();

    var myid;
    var tempVal;

    for (myKey in sortedArray) {
      myid = (isSafari) ? returnKey(window[this.categoryChildren][parent_value], sortedArray[myKey]) : myKey;
      if (!in_array(this.dontShow, myid)) {
	      theOption = new Option(window[this.categoryChildren][parent_value][myid],myid);
	      theSelect.options[k] = theOption;
	      if (defaultSelectedValue != null && defaultSelectedValue == myid) {
	      	theSelect.selectedIndex = k;
	      }
	      k++;
	    }
    }

    // insert pulldown
    if (current_num > 0) {
      parent_select.parentNode.appendChild(theSelect);
    } else {
      var theDiv = document.createElement("DIV");
	       theDiv.id = this.divIdPrefix+this.unique;
	       theDiv.className = 'categories_div';
	   theDiv.appendChild(theSelect);
      var obj = $(this.parentDivId);
	   obj.appendChild(theDiv);
    }

    this.selects[current_num] = theSelect.id;

    // reset the first option of the previous pulldown to 'remove'
    // note, start with > 1, because we do'nt want the very first pulldown changed
    if (current_num > 1) {
      var previous_num = current_num - 1;
      var previousObj;
      if (previousObj = $(this.selects[previous_num])) {
        previousObj.options[0].text = "-- Remove";
      }
    }

  } // end addSub()

} // end Object
