﻿    var fSelectSeed = 0;
    //{
    //  DIV: id | node
    //  data: JSON | {} | []
    //  mode: 0(single) | 1(multi)
    //  autocomplete: true | false
    //  formName: string
    //}
    published.Select = function (init, choiceUI) {
      if (!WAVE.exists(init)) throw "Select.ctor(init=null)";
      if (WAVE.strEmpty(init.DIV)) throw "Select.ctor(init.DIV=null)";

      var fDIV = WAVE.isString(init.DIV)
                    ? WAVE.id(init.DIV)
                    : init.DIV;
      if (fDIV === null) throw "Select.ctor(DIV=null)";

      var select = this,
          fChoiceUI = WAVE.isFunction(choiceUI)
                          ? choiceUI
                          : published.Choice,
          fChoiceBuilder = WAVE.isFunction(init.choiceBuilder) ? init.choiceBuilder : null,
          fData = null,
          fFormName = WAVE.strDefault(init.formName),
          fElemContainer = null,
          fElemCombobox = null,
          fElemDisplay = null,
          fElemArrow = null,
          fElemAutocomplete = null,
          fElemDropdown = null,
          fElemSelection = null,
          fElemAutocompleteContainer = null,
          fElemChoicesContainer = null,
          fDropdownShow = false,
          fAutocomplete = WAVE.strAsBool(init.autocomlete, true),
          fFilterTimer = null,
          fDisable = WAVE.strAsBool(init.disable),
          fMode = __parseMode(init.mode),
          fChoice = null,
          fSelectedChoices = {},
          fSelectedIds = [],
          fMatch = WAVE.isFunction(init.match) ? init.match : __match,
          fFilter = WAVE.isFunction(init.filter) ? init.filter : __filter,
          fUpdateData = WAVE.isFunction(init.updateData) ? init.updateData : __resetData,
          fButtonsNotFireFilter = [9, 16, 17, 18, 19, 20, 27, 37, 38, 39, 40],
          fIdSeed = "select_" + fSelectSeed++,
          fIds = {
            container : __IdFor("container"),
            combobox: __IdFor("combobox"),
            display: __IdFor("display"),
            arrow: __IdFor("select"),
            autocomlete: __IdFor("autocomplete"),
            dropdown: __IdFor("dropdown"),
            selection: __IdFor("selection"),
            autoContainer: __IdFor("autoContainer"),
            choicesContainer: __IdFor("choicesContainer")
          };

      WAVE.extend(select, WAVE.EventManager);

      function __IdFor(what) { return fIdSeed + "_" + what; }

      function __createElemet(tag, id, className) {
        var element = document.createElement(tag);
        element.id = id;
        if(!WAVE.strEmpty(className))
          element.className = className;
        return element;
      }

      function __parseMode(val) {
        return published.SELECT_MODES.Multi === val
                        ? published.SELECT_MODES.Multi
                        : published.SELECT_MODES.Single;
      }

      function __resetTimer() {
        if (fFilterTimer !== null) {
          clearTimeout(fFilterTimer);
          fFilterTimer = null;
        }
      }

      function __ensureInitData() {
        var data = init.data;
        if (typeof(data) !== tUNDEFINED && data !== null) {
          if (WAVE.isString(data)) {
            var res = WAVE.tryParseJSON(data);
            if (res.ok)
              fData = res.obj;
            else
              throw "Select.ctor(init.data invalid JSON)";
          } else
            fData = init.data;
          return;
        }
      }

      function __dropdownHide() {
        var args = {
          phase: published.EVT_PHASE_BEFORE,
          sender: select,
          abort: false,
          refresh: true
        };
        select.eventInvoke(published.EVT_SELECT_CLOSE, args);
        if (args.abort === true) return;

        __resetTimer();

        if (args.refresh === true) {
          fFilter([fChoice], "");
          fElemAutocomplete.value = "";
        }

        fDropdownShow = false;
        WAVE.addClass(fElemDropdown, published.CLS_SELECT_DROPDOWN_HIDDEN);
        WAVE.removeClass(fElemDropdown, published.CLS_SELECT_DROPDOWN_SHOWN);
        WAVE.removeEventHandler(window, "click", __outsideClickHandler);

        args.result = false;
        args.phase = published.EVT_PHASE_AFTER;
        delete args.abort;
        select.eventInvoke(published.EVT_SELECT_CLOSE, args);
      }

      function __dropdownShow() {
        var args = {
          phase: published.EVT_PHASE_BEFORE,
          sender: select,
          abort: false
        };
        select.eventInvoke(published.EVT_SELECT_OPEN, args);
        if (args.abort === true) return;

        fDropdownShow = true;
        WAVE.addClass(fElemDropdown, published.CLS_SELECT_DROPDOWN_SHOWN);
        WAVE.removeClass(fElemDropdown, published.CLS_SELECT_DROPDOWN_HIDDEN);
        WAVE.addEventHandler(window, "click", __outsideClickHandler);

        args.result = true;
        args.phase = published.EVT_PHASE_AFTER;
        delete args.abort;
        select.eventInvoke(published.EVT_SELECT_OPEN, args);
      }

      function __toggleDropdown(val) {
        if(typeof(val) === tUNDEFINED || val === null)
          val = !fDropdownShow;

        if (val === true)
          __dropdownShow();
        else
          __dropdownHide();
      }

      function __outsideClickHandler(e) {
        var target = e.target;
        if (!WAVE.isParentOf(fElemContainer, target)) {
          __dropdownHide();
        }
      }

      function __match(choice, term) {
        if (choice.value().toUpperCase().indexOf(term.toUpperCase()) > -1)
          return true;
        else
          return false;
      }

      function __filter(choices, term) {
        var arr = choices;
        for(var i = 0; i < arr.length; i++) {
          var choice = arr[i];
          if (choice === null) continue;
          var children = choice.children();

          if (children.length === 0 && choice.value() === null) continue;

          if (children.length > 0)
            __filter(children, term);
          else
            choice.visible(__match(choice, term));
        }
      }

      function __choiceUnselected(choice) {
        var args = {
          phase: published.EVT_PHASE_BEFORE,
          sender: select,
          abort: false
        };
        select.eventInvoke(published.EVT_SELECT_UNSELECT, args);
        if (args.abort === true) return;

        if (fMode === published.SELECT_MODES.Single) {
          fSelectedChoices = {};
          fSelectedIds = [];
        } else {
          delete fSelectedChoices[choice.id()];
          var idx = fSelectedIds.indexOf(choice.id());
          if (idx > -1)
            fSelectedIds.splice(idx, 1);
        }
        choice.destroyView();
        fElemSelection.value = select.value();

        args.result = fElemSelection.value;
        args.phase = published.EVT_PHASE_AFTER;
        delete args.abort;
        select.eventInvoke(published.EVT_SELECT_UNSELECT, args);
      }

      function __choiceSelected(choice) {
        var args = {
          phase: published.EVT_PHASE_BEFORE,
          sender: select,
          abort: false
        };
        select.eventInvoke(published.EVT_SELECT_SELECT, args);
        if (args.abort === true) return;

        if (fMode === published.SELECT_MODES.Single) {
          if (fSelectedIds.length > 0 && fSelectedIds[0] !== choice.id()) {
            var prev = fSelectedChoices[fSelectedIds[0]];
            prev.isSelected(false);
            prev.destroyView();
            fSelectedChoices = {};
            fSelectedIds = [];
          }
        }

        fSelectedChoices[choice.id()] = choice;
        fSelectedIds.push(choice.id());
        choice.renderSelection(fElemDisplay, function() {
          choice.isSelected(false);
          __choiceUnselected(choice);
        });
        fElemSelection.value = select.value();

        args.result = fElemSelection.value;
        args.phase = published.EVT_PHASE_AFTER;
        delete args.abort;
        select.eventInvoke(published.EVT_SELECT_SELECT, args);
      }

      function __choiceClickHandler(object, args) {
        if (args.phase === published.EVT_PHASE_BEFORE) return;

        var selected = args.sender.isSelected();
        if (fMode === published.SELECT_MODES.Single)
        {
          if (!selected) {
            if (!args.sender.isSelected(true)) return;
            __toggleDropdown();
            __choiceSelected(args.sender);
          }
        } else {
          if (selected) {
            if (args.sender.isSelected(false))
              __choiceUnselected(args.sender);
          }
          else
            if (args.sender.isSelected(true))
              __choiceSelected(args.sender);
        }
      }

      function __destroyChoice() {
        fChoice.eventUnbind(published.EVT_SELECT_CHOICE_CLICK, __choiceClickHandler);
        fChoice.destroy();
        fChoice = null;
      }

      function __resetData(data) {
        var empty = typeof(data) === tUNDEFINED || data === null;
        if (empty && fChoice !== null) {
          __destroyChoice();
          return;
        }

        fSelectedIds = [];
        fSelectedChoices = {};

        if (fChoice !== null)
          __destroyChoice();

        if (!empty) {
          fChoice = new fChoiceUI({data: data, DIV: fElemChoicesContainer, builder: fChoiceBuilder, disable: fDisable});
          fChoice.eventBind(published.EVT_SELECT_CHOICE_CLICK, __choiceClickHandler);
        }
      }

      function __tv(choice, val) {
        var ch = choice.children(),
            l = ch.length;
        if (l === 0) {
          if (choice.trySetValue(val)) {
            __choiceSelected(choice);
            return true;
          }
        } else {
          var result = false;
          for(var i = 0; i < l; i++) {
            var s = __tv(ch[i], val);
            result = result && s;
          }
          return result;
        }
      }

      function __setValue(val) {
        if (fChoice === null) return false;

        fChoice.resetSelection();
        for(var j = 0, k = fSelectedIds.length; j < k; j++) {
           fSelectedChoices[fSelectedIds[j]].destroyView();
        }
        fSelectedIds = [];
        fSelectedChoices = {};
        if (fMode === published.SELECT_MODES.Single) {
          return __tv(fChoice, val);
        } else {
          var vs = val.split(';');
          var res = false, tr;
          for(var i = 0, l = vs.length; i < l; i++) {
            tr = __tv(fChoice, vs[i]);
            res = res && tr;
          }
          return res;
        }
      }

      function __build() {
        var cls = fMode === published.SELECT_MODES.Multi ?
                  published.CLS_SELECT_MODE_MULTI :
                  published.CLS_SELECT_MODE_SINGLE;

        fElemContainer = __createElemet("div", fIds.container, published.CLS_SELECT_CONTAINER + " " + cls);
        fDIV.appendChild(fElemContainer);

        fElemSelection = __createElemet("input", fIds.selection);
        fElemSelection.type = "hidden";
        fElemContainer.appendChild(fElemSelection);
        if (!WAVE.strEmpty(fFormName))
          fElemSelection.name = fFormName;

        fElemCombobox = __createElemet("div", fIds.combobox, published.CLS_SELECT_COMBOBOX);
        fElemContainer.appendChild(fElemCombobox);

        fElemDisplay = __createElemet("div", fIds.display, published.CLS_SELECT_DISPLAY);
        fElemCombobox.appendChild(fElemDisplay);

        fElemArrow = document.createElement("div");
        fElemArrow.className = published.CLS_SELECT_ARROW;
        fElemCombobox.appendChild(fElemArrow);
        WAVE.addEventHandler(fElemArrow, "click", function() { __toggleDropdown(); });

        fElemDropdown = __createElemet("div", fIds.dropdown, published.CLS_SELECT_DROPDOWN + " " + published.CLS_SELECT_DROPDOWN_HIDDEN);
        fElemDropdown.style.zIndex = CURTAIN_ZORDER + fCurtains.length + 1;
        fElemContainer.appendChild(fElemDropdown);

        fElemAutocompleteContainer = __createElemet("div", fIds.autoContainer, published.CLS_SELECT_AUTO_CONTAINER);
        fElemDropdown.appendChild(fElemAutocompleteContainer);

        fElemChoicesContainer = __createElemet("div", fIds.choicesContainer, published.CLS_SELECT_CHOICES_CONTAINER);
        fElemDropdown.appendChild(fElemChoicesContainer);

        if (fAutocomplete) {
          fElemAutocomplete = __createElemet("input", fIds.autocomlete, published.CLS_SELECT_AUTOCOMPETE);
          fElemAutocomplete.placeholder = "Start enter..";
          if (fMode === published.SELECT_MODES.Single)
            fElemAutocompleteContainer.appendChild(fElemAutocomplete);
          else
            fElemCombobox.appendChild(fElemAutocomplete);

          WAVE.addEventHandler(fElemAutocomplete, "keyup", function(e) {
            if (fButtonsNotFireFilter.indexOf(e.keyCode) > -1)
              return;

            __resetTimer();
            fFilterTimer = setTimeout(function() {
              fFilter([fChoice], fElemAutocomplete.value);
              if (!fDropdownShow)
                __dropdownShow();
            }, 800);
          });
          WAVE.addEventHandler(fElemAutocomplete, "click", __dropdownShow);
        }
        __resetData(fData);
      }

      select.selected = function() {
        return fSelectedChoices;
      };

      select.mode = function() { return fMode; }

      select.value = function(val) {
        if(typeof(val) === tUNDEFINED) {
          var result = "";
          for(var v in fSelectedChoices)
            result += fSelectedChoices[v].key() + ";";
          return result.slice(0, -1);
        } else
          __setValue(val.toString());
      };

      select.data = function(val) {
        if (typeof(val) === tUNDEFINED)
          return val;

        fData = val;
        __resetData(fData);
      };

      select.updateData = function(val) {
        fUpdateData(val);
      };

      select.filter = function(term) {
        fFilter([fChoice], typeof(term) === tUNDEFINED ? fElemAutocomplete.value : term);
      };

      select.hasChoice = function() { return fChoice !== null; };

      select.latchAllEvents = function(delta) {
        select.eventInvocationSuspendCount += delta;
        if(fChoice !== null) fChoice.latchAllEvents(delta);
      };

      __ensureInitData();
      __build();

      return select;
    };//Select

    published.CLS_SELECT_CHOICE = "wvChoice";
    published.CLS_SELECT_CHOICE_DISABLED = "wvChoiceDisabled";
    published.CLS_SELECT_CHOICE_SELECTED = "wvSelected";
    published.CLS_SELECT_CHOICE_PARENT = "wvChoiceParent";
    published.CLS_SELECT_CHOICE_PARENT_LABELED = "wvChoiceParentLabeled";
    published.CLS_SELECT_CHOICE_LABEL = "wvChoiceLabel";
    published.CLS_SELECT_CHOICE_VALUE_BOX = "wvChoiceValueBox";
    published.CLS_SELECT_CHOICE_UNSELECT = "wvChoiseUnselect";

    published.EVT_SELECT_CHOICE_SELECTED = "wv-choice-selected";
    published.EVT_SELECT_CHOICE_UNSELECTED = "wv-choice-unselected";
    published.EVT_SELECT_CHOICE_CLICK = "wv-choise-choice-click";

    var fChoiceSeed = 0;
    published.Choice = function(init) {

      var choice = this,
          fDIV = init.DIV,
          fChildren = [],
          fDisable = WAVE.strAsBool(init.disable, false),
          fVisible = true,
          fIsSelected = false,
          fRendered = false,
          fData = init.data,
          fKey = WAVE.strEmpty(init.key) ? null : init.key,
          fValue = WAVE.strEmpty(init.value) ? null : init.value,
          fElemValueBox = null,
          fElemChoice = null,
          fElemUnselect = null,
          fStlDisplay = null,
          fCLS = WAVE.strDefault(init.cls),
          fOnCloseClick = null,
          fOnClick = WAVE.isFunction(init.onclick) ? init.onclick : __click,
          fBuilder = init.builder,
          fId = "wv_choice_" + fChoiceSeed++,
          fIds = {
            unselect: fId + "_unselect",
            valueBox: fId + "_value"
          };

      WAVE.extend(choice, WAVE.EventManager);

      function __select(tryValue) {
        if (fIsSelected) return false;

        var args = {
          phase: published.EVT_PHASE_BEFORE,
          sender: choice,
          abort: false
        };
        choice.eventInvoke(published.EVT_SELECT_CHOICE_SELECTED, args);
        if (args.abort === true) return false;

        fIsSelected = typeof(tryValue) === tUNDEFINED ? true : fKey === tryValue;
        if (fIsSelected)
          WAVE.addClass(fElemChoice, published.CLS_SELECT_CHOICE_SELECTED);

        args.result = fIsSelected;
        args.phase = published.EVT_PHASE_AFTER;
        delete args.abort;
        choice.eventInvoke(published.EVT_SELECT_CHOICE_SELECTED, args);

        return fIsSelected;
      }

      function __unselect() {
        if (!fIsSelected) return false;

        var args = {
          phase: published.EVT_PHASE_BEFORE,
          sender: choice,
          abort: false
        };
        choice.eventInvoke(published.EVT_SELECT_CHOICE_UNSELECTED, args);
        if (args.abort === true) return false;

        fIsSelected = false;
        WAVE.removeClass(fElemChoice, published.CLS_SELECT_CHOICE_SELECTED);

        args.result = false;
        args.phase = published.EVT_PHASE_AFTER;
        delete args.abort;
        choice.eventInvoke(published.EVT_SELECT_CHOICE_UNSELECTED, args);

        return true;
      }

      function __toggleSelection(val, tryValue) {
        var result;
        if (fChildren.length > 0) {
          for(var i = 0, l = fChildren.length; i < l; i++) {
            if (!WAVE.strEmpty(tryValue))
              result = result || fChildren[i].trySetValue(tryValue);
            else
              result = result && fChildren[i].isSelected(val);
          }
          return result;
        }
        else {
          if (val === true || !WAVE.strEmpty(tryValue))
            return __select(tryValue);
          else
            return __unselect();
        }
      }

      function __click(e, o) {
        if (fDisable === true)
          return;

        var args = {
          phase: published.EVT_PHASE_BEFORE,
          sender: choice,
          abort: false
        };
        choice.eventInvoke(published.EVT_SELECT_CHOICE_CLICK, args);
        if (args.abort === true) return;

        args.phase = published.EVT_PHASE_AFTER;
        delete args.abort;
        choice.eventInvoke(published.EVT_SELECT_CHOICE_CLICK, args);
      }

      function __hide() {
        if (!fVisible) return;

        fVisible = false;
        if (fStlDisplay === null)
          fStlDisplay = WAVE.styleOf(fElemChoice, "display");
        fElemChoice.style.display = "none";
      }

      function __show() {
        if (fVisible) return;

        fVisible = true;
        fElemChoice.style.display = fStlDisplay === null ? "block" : fStlDisplay;
      }

      function __toggleVisibility(val) {
        if (typeof(val) === tUNDEFINED || val === null)
          val = !fVisible;

        if (val === true)
          return __show();
        else
          return __hide();
      }

      function __selectedEventHandler(object, args) {
        choice.eventInvoke(published.EVT_SELECT_CHOICE_SELECTED, args);
      }

      function __unselectedEventHandler(object, args) {
        choice.eventInvoke(published.EVT_SELECT_CHOICE_UNSELECTED, args);
      }

      function __clickEventHandler(object, args) {
        choice.eventInvoke(published.EVT_SELECT_CHOICE_CLICK, args);
      }

      function __addChild(child) {
        child.eventBind(published.EVT_SELECT_CHOICE_SELECTED, __selectedEventHandler);
        child.eventBind(published.EVT_SELECT_CHOICE_UNSELECTED, __unselectedEventHandler);
        child.eventBind(published.EVT_SELECT_CHOICE_CLICK, __clickEventHandler);
        fChildren.push(child);
      }

      function __createChild(cData, cDiv) {
        var child = new published.Choice({data: cData, DIV: cDiv, builder: fBuilder});
        __addChild(child);
      }

      function __onClickInvoke(e) { fOnClick(e, choice); }

      function __initElemChoice() {
        fElemChoice = document.createElement("div");
        fElemChoice.id = fId;
        fDIV.appendChild(fElemChoice);
        WAVE.addEventHandler(fElemChoice, "click", __onClickInvoke);
        if (!fDisable)
          fElemChoice.className = published.CLS_SELECT_CHOICE;
        else
          fElemChoice.className = published.CLS_SELECT_CHOICE_DISABLED;
        if (fCLS !== null)
          WAVE.addClass(fElemChoice, fCLS);
      }

      function __buildAsKeyValue(key, value) {
        __initElemChoice();
        fElemChoice.innerHTML = value;
        fValue = value;
        fKey = key;
      }

      function __buildAsArray(arrValue) {
        fElemChoice = document.createElement("div");
        fElemChoice.id = fId;
        fElemChoice.className = published.CLS_SELECT_CHOICE_PARENT;
        fDIV.appendChild(fElemChoice);

        for(var i = 0; i < arrValue.length; i++) {
          var value = arrValue[i];
          __createChild(value, fElemChoice);
        }
      }

      function __buildAsObject(objValue) {
        var keys = Object.keys(objValue),
            key,
            value,
            label;

        if (keys.length === 1) {
          key = keys[0];
          value = objValue[key];
          if (WAVE.isString(value) || !WAVE.isMapOrArray(value)) {
            __buildAsKeyValue(key, value.toString());
          } else {
            fElemChoice = document.createElement("div");
            fElemChoice.id = fId;
            fElemChoice.className = published.CLS_SELECT_CHOICE_PARENT + " " +
                                    published.CLS_SELECT_CHOICE_PARENT_LABELED;
            fDIV.appendChild(fElemChoice);

            label = document.createElement("div");
            label.className = published.CLS_SELECT_CHOICE_LABEL;
            label.innerHTML = key;
            fElemChoice.appendChild(label);

            __createChild(value, fElemChoice);
          }
        } else {
          fElemChoice = document.createElement("div");
          fElemChoice.id = fId;
          fElemChoice.className = published.CLS_SELECT_CHOICE_PARENT + " " +
                                  published.CLS_SELECT_CHOICE_PARENT_LABELED;
          fDIV.appendChild(fElemChoice);

          for(key in objValue) {
            label = document.createElement("div");
            label.className = published.CLS_SELECT_CHOICE_LABEL;
            label.innerHTML = key;
            fElemChoice.appendChild(label);

            value = objValue[key];
            __createChild(value, fElemChoice);
          }
        }
      }

      function __build(data, DIV) {
        if (typeof(data) === tUNDEFINED || data === null)
          return;

        if (WAVE.isString(data))      __buildAsKeyValue(data, data);
        else if (WAVE.isArray(data))  __buildAsArray(data);
        else if (WAVE.isObject(data)) __buildAsObject(data);
        else __buildAsKeyValue(data.toString(), data.toString());
      }

      function __destroyView() {
        WAVE.removeEventHandler(fElemUnselect, "click", fOnCloseClick);
        WAVE.removeElem(fIds.unselect);
        WAVE.removeElem(fIds.valueBox);
        fOnCloseClick = null;
        fRendered = false;
      }

      function __destroy() {
        WAVE.removeEventHandler(fElemChoice, "click", __onClickInvoke);
        WAVE.removeElem(fId);
        choice.eventUnbind(published.EVT_SELECT_CHOICE_SELECTED, __selectedEventHandler);
        choice.eventUnbind(published.EVT_SELECT_CHOICE_UNSELECTED, __unselectedEventHandler);
        choice.eventUnbind(published.EVT_SELECT_CHOICE_CLICK, __clickEventHandler);
        for(var i = 0; i < fChildren.length; i++)
          fChildren[i].destroy();
      }

      choice.disable = function(val) {
        if (typeof(val) === tUNDEFINED || val === null) {
          if (fDisable === null)
            fDisable = fChildren.length > 0;
          return fDisable;
        }
        fDisable = WAVE.strAsBool(val, true);
          //TODO fire selectable change
      };

      choice.isSelected = function(val) {
        if (typeof(val) === tUNDEFINED || val === null)
          return fIsSelected;
        return __toggleSelection(val);
      };

      choice.trySetValue = function(val) {
        if (typeof(val) === tUNDEFINED || val === null) return false;

        return __toggleSelection(null, val);
      }

      choice.resetSelection = function() {//TODO add val
        if (fChildren.length === 0)
          __toggleSelection(false);
        else
          for(var i = 0, l = fChildren.length; i < l; i++)
            fChildren[i].resetSelection();
      }

      choice.visible = function(val) {
        if (typeof(val) === tUNDEFINED || val === null)
          return fVisible;

        return __toggleVisibility(val);
      };

      choice.disable = function() { };

      choice.id = function() { return fId; };
      choice.key = function() { return fKey; };
      choice.value = function() { return fValue; };
      choice.children = function() { return fChildren; };
      choice.elem = function() { return fElemChoice; };

      choice.addChild = function(child) {
        __addChild(child);
      };

      choice.renderSelection = function(div, onCloseClick) {
        if (!fIsSelected ||
            fRendered === true ||
            typeof(div) === tUNDEFINED ||
            div === null)
          return;

        var html = "<div>@value@</div>" +
                   "<div class='@clsUnselect@' id='@idUnselect@'>";
        var view = WAVE.strHTMLTemplate(html, {
          value : fValue,
          clsUnselect : published.CLS_SELECT_CHOICE_UNSELECT,
          idUnselect : fIds.unselect
        });
        fElemValueBox = document.createElement("div");
        fElemValueBox.className = published.CLS_SELECT_CHOICE_VALUE_BOX;
        fElemValueBox.innerHTML = view;
        fElemValueBox.id = fIds.valueBox;

        div.appendChild(fElemValueBox);

        fElemUnselect = WAVE.id(fIds.unselect);
        fOnCloseClick = function() { onCloseClick(choice); };
        fRendered = true;
        WAVE.addEventHandler(fElemUnselect, "click", fOnCloseClick);
      };

      choice.destroyView = function() {
        __destroyView();
      };

      choice.destroy = function() {
        __destroyView();
        __destroy();
      };

      choice.latchAllEvents = function(delta) {
        choice.eventInvocationSuspendCount += delta;
        for(var i = 0, l = fChildren.length; i < l; i++)
          fChildren[i].eventInvocationSuspendCount += delta
      };

      if (WAVE.isFunction(fBuilder)) {
        __initElemChoice();
        fBuilder(choice, fData, fElemChoice);
      }
      else
        __build(fData, fDIV);

      return choice;
    };//Choice