<?xml version="1.0"?>

<bindings   id="mailBindings"
            xmlns="http://www.mozilla.org/xbl"
            xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  
  <!-- Message Pane Widgets -->
  <binding id="mail-emailaddress" extends="chrome://global/content/xulBindings.xml#basetext">
    <content excludes="observes,template">
      	<xul:box inherits="orient" autostretch="never" flex="1">
          <xul:box orient="vertical"  autostretch="never" flex="1">
            <xul:text class="emailDisplayButton" context="emailAddressPopup" inherits="value,accesskey,crop"/>
          </xul:box>
          <xul:image class="emailDisplayImage" inherits="src"/>
        </xul:box>
    </content>
    
    <interface>  
      <method name="setTextAttribute">
        <argument name="attributeName"/>
        <argument name="attributeValue"/>
        <body>
          <![CDATA[            
            var textNode = document.getAnonymousNodes(this)[0].firstChild.firstChild;
            textNode.setAttribute(attributeName, attributeValue);
          ]]>
        </body>
      </method>

      <method name="getTextAttribute">
        <argument name="attributeName"/>
        <argument name="attributeValue"/>
        <body>
          <![CDATA[            
            var textNode = document.getAnonymousNodes(this)[0].firstChild.firstChild;
            return textNode.getAttribute(attributeName, attributeValue);
          ]]>
        </body>
      </method>
    </interface>
  </binding>

  <binding id="search-menulist-abstract" extends="xul:box">
    <content>
      <xul:menulist inherits="flex" oncommand="this.parentNode.onSelect(event)">
        <xul:menupopup/>
      </xul:menulist>
    </content>

    <interface>
      <property readonly="true" name="validityManager">
        <![CDATA[
           Components.classes['mozilla.mail.search.validityManager.1'].getService(Components.interfaces.nsIMsgSearchValidityManager);
        ]]>
      </property>
      <property name="searchScope" onget="return this.internalScope;">
        <!-- scope ID - retrieve the table -->
        <setter>
          <![CDATA[
            // if scope isn't changing this is a noop
            if (this.internalScope == val) return;

            this.internalScope = val;
            this.refreshList();
            var targets = this.targets;
            if (targets) {
              for (var i=0; i< targets.length; i++) {
                targets[i].searchScope = val;
              }
            }
          ]]>
        </setter>
      </property>

      <property name="validityTable" readonly="true" onget="return this.validityManager.getTable(this.searchScope)"/>

      <property name="valueStrings" readonly="true">
        <getter>
          <![CDATA[
            var strings = new Array;
            var ids = this.valueIds;
            var bundle = this.stringBundle;
            for (var i=0; i<ids.length; i++)
                strings[i] = this.stringBundle.GetStringFromID(ids[i]);
            return strings;
          ]]>
        </getter>
      </property>
      <property name="targets" readonly="true">
        <getter>
          <![CDATA[
            var forAttrs =  this.getAttribute("for");
            if (!forAttrs) return null;
            var targetIds = forAttrs.split(",");
            if (targetIds.length == 0) return null;

            var targets = new Array;
            var j=0;
            for (var i=0; i<targetIds.length;i++) {
              var target = document.getElementById(targetIds[i]);
              if (target) targets[j++] = target;
            }
            return targets;
          ]]>
        </getter>
      </property>

      <!-- value forwards to the internal menulist's "data" attribute -->
      <property name="value" onget="return document.getAnonymousNodes(this)[0].selectedItem.getAttribute('data');">
        <setter>
          <![CDATA[
            var menulist = document.getAnonymousNodes(this)[0];
            var dataItems = menulist.getElementsByAttribute("data", val);
            if (dataItems.length > 0)
                menulist.selectedItem = dataItems[0];
          ]]>
        </setter>
      </property>
      <method name="refreshList">
        <body>
          <![CDATA[
            var menuItemIds = this.valueIds;
            var menuItemStrings = this.valueStrings;

            var menulist = document.getAnonymousNodes(this)[0];
            var popup = menulist.firstChild;

            // save our old "data" so we can restore it later
            var oldData = menulist.data;

            // remove the old popup children
            while (popup.hasChildNodes())
              popup.removeChild(popup.lastChild);

            var newSelection;
            for (var i=0; i<menuItemIds.length; i++) {
              // create the menuitem
              var menuitem = document.createElement("menuitem");
              menuitem.setAttribute("value", menuItemStrings[i]);
              menuitem.setAttribute("data", menuItemIds[i]);
              popup.appendChild(menuitem);

              // try to restore the selection
              if (!newSelection || oldData == menuItemIds[i].toString()) {
                newSelection = menuitem;
              }
            }

            // now restore the selection
            menulist.selectedItem = newSelection
          ]]>
        </body>
      </method>
      <method name="onSelect">
        <argument name="event"/>
        <body>
          <![CDATA[
            var menulist = document.getAnonymousNodes(this)[0];

            // notify targets
            var targets = this.targets;
            if (targets) {
              for (var i=0; i< targets.length; i++) {
                targets[i].parentValue = menulist.data;
              }
            }
          ]]>
        </body>
      </method>
    </interface>
  </binding>

  <!-- searchattribute - Subject, Sender, To, CC, etc. -->
  <binding id="searchattribute"
           extends="chrome://messenger/skin/mailWidgets.xml#search-menulist-abstract">
    <interface>
      <property name="stringBundle">
          <![CDATA[
           srGetStrBundle("chrome://messenger/locale/search-attributes.properties");
          ]]>
      </property>
      <property name="valueIds" readonly="true">
        <getter>
          <![CDATA[
            var length = new Object;
            return this.validityTable.getAvailableAttributes(length);
          ]]>
        </getter>
      </property>
    </interface>
  </binding>

  <!-- searchoperator - Contains, Is Less than, etc -->
  <binding id="searchoperator"
           extends="chrome://messenger/skin/mailWidgets.xml#search-menulist-abstract">
    <interface>
      <property name="stringBundle">
          <![CDATA[
            srGetStrBundle("chrome://messenger/locale/search-operators.properties");
          ]]>
      </property>
      <property name="valueIds" readonly="true">
        <getter>
          <![CDATA[
            var length = new Object;
            return this.validityTable.getAvailableOperators(this.searchAttribute,length);
          ]]>
        </getter>
      </property>
      <property name="parentValue">
        <setter>
          <![CDATA[
            if (this.searchAttribute == val) return;
            this.searchAttribute = val;
            this.refreshList();
          ]]>
        </setter>
        <getter>
          <![CDATA[
            return this.searchAttribute;
          ]]>
        </getter>
      </property>
    </interface>
  </binding>

  <!-- searchvalue - a widget which dynamically changes it's user interface
       depending on what type of data it's supposed to be showing
       currently handles arbitrary text entry, and menulists for priority and
       status
  -->
  <binding id="searchvalue" extends="xul:deck">
    <!-- yeah yeah, this stuff needs to be localized. I'm working on it! -->
    <content>
      <xul:textfield flex="1" />
      <xul:menulist flex="1" >
        <xul:menupopup>
          <xul:menuitem value="Lowest"/>
          <xul:menuitem value="Low"/>
          <xul:menuitem value="Normal"/>
          <xul:menuitem value="High"/>
          <xul:menuitem value="Highest"/>
        </xul:menupopup>
      </xul:menulist>
      <xul:menulist flex="1" >
        <xul:menupopup>
          <xul:menuitem value="read"/>
          <xul:menuitem value="replied"/>
        </xul:menupopup>
      </xul:menulist>
    </content>
    <interface>
      <!-- parentValue forwards to the attribute -->
      <property name="parentValue" onset="this.searchAttribute=val;"
                                   onget="return this.searchAttribute;"/>
      <property name="searchAttribute" onget="return this.internalAttribute;">
        <setter>
          <![CDATA[
            // noop if we're not changing it
            if (this.internalAttribute == val) return;
            this.internalAttribute = val;
            // we inherit from a deck, so just use it's index attribute
            // to hide/show widgets
            if (val == Components.interfaces.nsMsgSearchAttrib.Priority)
              this.setAttribute("index", "1");
            else if (val == Components.interfaces.nsMsgSearchAttrib.MsgStatus)
              this.setAttribute("index", "2");
            else
              this.setAttribute("index", "0");
          ]]>
        </setter>
      </property>
      <property name="value" onget="return this.internalValue;">
        <setter>
          <![CDATA[
          // val is a nsIMsgSearchValue object
          this.internalValue = val;
          var attrib = val.attrib;
          this.searchAttribute = attrib;
          if (attrib == Components.interfaces.nsMsgSearchAttrib.Priority)
            document.getAnonymousNodes(this)[1].data=val.priority;
          else if (attrib == Components.interfaces.nsMsgSearchAttrib.MsgStatus)
            document.getAnonymousNodes(this)[2].data=val.status;
          else
            document.getAnonymousNodes(this)[0].value = val.str;
          ]]>
        </setter>
      </property>
      <method name="save">
        <body>
          <![CDATA[
            var searchValue = this.value;
            var searchAttribute = this.searchAttribute;
            var nsMsgSearchAttrib = Components.interfaces.nsMsgSearchAttrib;

            searchValue.attrib = searchAttribute;
            if (searchAttribute == nsMsgSearchAttrib.Priority)
               searchValue.priority = document.getAnonymousNodes(this)[1].selectedItem.data;
            else if (searchAttribute == nsMsgSearchAttrib.MsgStatus)
               searchValue.status = document.getAnonymousNodes(this)[2].selectedItem.data;
            else
               searchValue.str = document.getAnonymousNodes(this)[0].value;
          ]]>
        </body>
      </method>
      <method name="saveTo">
        <argument name="searchValue"/>
        <body>
          <![CDATA[
            this.internalValue = searchValue;
            this.save();
          ]]>
        </body>
      </method>
    </interface>
  </binding>
  <binding id="searchterm" extends="xul:box">
    <interface>
      <!-- the actual nsIMsgSearchTerm object -->
      <property name="searchTerm" onget="return this.internalSearchTerm">
        <setter>
          <![CDATA[
            this.internalSearchTerm = val;

            var term = val;
            // val is a nsIMsgSearchTerm
            var searchAttribute=this.searchattribute;
            var searchOperator=this.searchoperator;
            var searchValue=this.searchvalue;

            // now reflect all attributes of the searchterm into the widgets
            if (searchAttribute) searchAttribute.value = term.attrib;
            if (searchOperator) searchOperator.value = val.op;
            if (searchValue) searchValue.value = term.value;

            this.booleanAnd = val.booleanAnd;
          ]]>
        </setter>
      </property>
 
      <property name="searchScope">
        <getter>
          <![CDATA[
             var searchAttribute = this.searchattribute;
             if (searchAttribute)
               return searchAttribute.searchScope;
             return undefined;
           ]]>
        </getter>
        <setter>
          <![CDATA[
            var searchAttribute = this.searchattribute;
            if (searchAttribute) searchAttribute.searchScope=val;
           ]]>
        </setter>
      </property>
      <!-- the three tags that make up a term - to use, set the
           attribute in the XUL to the ID of the term.
        -->
      <property name="searchattribute" 
                onget="return document.getElementById(this.getAttribute('searchattribute'));"
                onset="this.setAttribute('searchattribute',val.id)"/>

      <property name="searchoperator" 
                onget="return document.getElementById(this.getAttribute('searchoperator'));"
                onset="this.setAttribute('searchoperator',val.id)"/>

      <property name="searchvalue" 
                onget="return document.getElementById(this.getAttribute('searchvalue'));"
                onset="this.setAttribute('searchvalue',val.id)"/>
      <property name="booleanNodes">
        <![CDATA[
          null;
        ]]>
      </property>
      <property name="stringBundle">
          <![CDATA[
             srGetStrBundle("chrome://messenger/locale/search.properties");
          ]]>
      </property>
      <property name="booleanAnd" onget="return this.internalBooleanAnd">
        <setter>
          <![CDATA[
            // whenever you set this, all nodes in booleanNodes
            // are updated to reflect the string

            if (this.internalBooleanAnd == val) return;
            this.internalBooleanAnd = val;

            var booleanNodes = this.booleanNodes;
            if (!booleanNodes) return;

            var stringBundle = this.stringBundle;
            var andString = val ? "And" : "Or";
            for (var i=0; i<booleanNodes.length; i++) {
              try {              
                var staticString =
                    stringBundle.GetStringFromName("search" + andString + i);
                if (staticString && staticString.length>0)
                    booleanNodes[i].setAttribute("value", staticString);
              } catch (ex) { /* no error, means string not found */}
            }
          ]]>
        </setter>
      </property>
      <method name="save">
        <body>
          <![CDATA[
            var searchTerm = this.searchTerm;
            searchTerm.attrib = this.searchattribute.value;
            searchTerm.op = this.searchoperator.value;
            if (this.searchvalue.value)
              this.searchvalue.save();
            else
              this.searchvalue.saveTo(searchTerm.value);
            searchTerm.value = this.searchvalue.value;
            searchTerm.booleanAnd = this.booleanAnd;
          ]]>
        </body>
      </method>
      <!-- if you have a search term element with no search term -->
      <method name="saveTo">
        <argument name="searchTerm"/>
        <body>
          <![CDATA[
            this.internalSearchTerm = searchTerm;
            this.save();
          ]]>
        </body>
      </method>
    </interface>
  </binding>
</bindings>
