/**
 * Copyright 2006 Google, All Rights Reserved.
 * @author Harrison Ting (hting@google.com)
 *
 * @fileoverview
 * <p>
 * This document describes the JavaScript code for showing
 * multiple versions of content.  It is used in the
 * <a href="http://www.google.com/apis/adwords/developer/index.html">AdWords
 * API Developer's Guide</a>, by way of version links in the upper
 * right corner.  On a page-by-page basis, the links let you
 * show a single version, or show that version with its differences
 * against any previous version by underlining added content and striking
 * through deleted content.
 * </p>
 *
 * <table><tr><td style="background-color: #EEE; padding: .6em 1.5em 0em 1em;
 * font-size: 90%;">
 * <p><b>Page Contents</b></p>
 * <ul>
 *   <li><a href="#walkthrough">How Versioning API Operates</a></li>
 *   <li><a href="#globals">Global Variables</a></li>
 *   <li><a href="#versionranges">Version Ranges</a></li>
 *   <li><a href="#lookuptable">Version Lookup Table</a></li>
 *   <li><a href="#classes">Class Attributes</a></li>
 *   <li><a href="#versionlinks">Version Links</a></li>
 *   <li><a href="#htmlexamples">HTML Examples</a></li>
 * </ul></td></tr></table>
 *
 * <h4 id="walkthrough">How Versioning API Operates</h4>
 * <blockquote>
 *
 *     <blockquote>
 *     NOTE - Versioning presumes that differences ("diffs") in the content are
 *     already marked with <a href="#classes">class attributes</a>.  This
 *     can be done manually or with a doc generator.
 *
 *     <blockquote>
 *     NOTE - The main reason this API is so complex is because it has
 *     been optimized so that switching between versions in a browser
 *     is very fast.  This is done by reducing the amount of JavaScript
 *     code that needs to run by pre-processing each page in Java
 *     and determining of all possible views, which views are actually
 *     present.  There is one view for each single version, and one view
 *     for each unordered pair of versions.
 *     (Given <var>n</var> available versions, there are n + n choose 2
 *     possible views.  For example, 3 available versions produces 3 + 3!/(2!1!)
 *     = 6 views).
 *     This is done by having the Java code parse the text for version
 *     range tags, "register" them, and then build a
 *     <a href="#lookuptable">lookup table</a> and embed it into the
 *     HTML page.  When a user chooses a view, the JavaScript then simply
 *     reads this table and applies the proper styles.
 *     </blockquote>
 *     <p>
 *     This brief walkthrough takes you through the steps from a user choosing
 *     a version in a document which starts JavaScript running and the general
 *     operations that occur.  It should help you understand how versioning works.
 *     Let's say the document has a "v5" link for version 5 and
 *     a "v4" diff link below it for diffing against version 4,
 *     as illustrated in
 *     <a href="http://www.google.com/apis/adwords/developer/index.html">AdWords
 *     API Developer's Guide</a>.
 *     </p>
 *     <p>
 *     <b>Click on view link</b> -   The v5 version link has
 *     <a href="#htmlform"><tt>showVersion(5)</tt></a> assigned to it.
 *     When a user clicks on the v5 link, this function is called:
 *     <ul>
 *       <tt><a href="GLOBALS.html#!s!showVersion">showVersion(<i>viewVersion</i>, <i>diffVersion</i>)</a></tt><br>
 *     </ul>
 *     </p>
 *     <p>
 *     In our example, this function performs the following actions by setting
 *     properties on <tt>class</tt> attributes:
 *     <ol>
 *       <li> Show content that belongs to version 5
 *       <li> Hide content that does not belong to version 5
 *       <li> Make the v5 link bold, dim the v4 link and set the diff links
 *     </ol>
 *     <p>
 *     <b>Click on diff link</b> -   The v4 diff version link has
 *     <a href="#htmlform"><tt>diffCurrentVersion(4)</tt></a> assigned to it
 *     When a user clicks on this, this function is called:
 *     <ul>
 *       <tt><a href="GLOBALS.html#!s!diffCurrentVersion">diffCurrentVersion(<i>diffVersion</i>)</a></tt><br>
 *     </ul>
 *     <p>
 *     In our example, this function performs the following actions by setting
 *     properties on <tt>class</tt> attributes on the content:
 *     <ol>
 *       <li> Show content that belongs to version 4 or 5
 *       <li> Hide content that does not belong to version 4 or 5
 *       <li> Underline content that belongs to version 5 but not 4
 *       <li> Strikethrough content that belongs to 4 but not 5
 *       <li> Make the v4 diff link bold, dim other diff links
 *     </ol>
 *     <p>
 *     The rest of this section describes how Versioning API works,
 *     using the same example.
 *     </p>
 *
 * </blockquote>
 *
 * <h4 id="globals">Global Variables</h4>
 * <blockquote>
 *
 * To use this JavaScript, the following global variables must be set:
 * <ul>
 *   <li><tt>versionFrom</tt> - The lowest version that can be shown.</li>
 *       In our example, this would be set to value 4.
 *
 *   <li><tt>versionTo</tt> - The highest version that can be shown.</li>
 *       In our example, this would be set to value 5.
 *
 *   <li><tt>versionRanges</tt> - Array of all unique version range
 *       class attribute names present on this web page. Further
 *       described below. </li>
 *
 *   <li><tt>versionLookupTable</tt> - Multi-dimensional array to store which
 *       version ranges should be shown when, and in what style.
 *       Further described below.</li>
 * </ul>
 *
 * </blockquote>
 *
 * <h4 id="versionranges">Version Ranges</h4>
 * <blockquote>
 *
 *     <p>
 *     The global variable <tt>versionRanges</tt> holds an array of all unique
 *     version range class attribute names present on this web page.
 *     Note that <tt>up</tt> means "all later versions", so that <tt>v5-up</tt>
 *     means "version 5 or later version" (that is, v5, v6, v7, or later).
 *     </p>
 *
 *     Example:
 * <pre>
 * var versionRanges =                                    // Defines class:
 *           new Array(new Array('v5-up', 'ShowHide'),    // 'v5-upShowHide'
 *                     new Array('v5-up', ''));           // 'v5-up'
 *                     new Array('v5-up a', ''));         // 'v5-up a'</pre>
 *     <p>
 *     This example indicates that the only class attributes present on
 *     the page are:
 *     <ul>
 *       <li> <tt>v5-upShowHide</tt> - Show or hide text in this element
 *       <li> <tt>v5-up</tt> - Mark as added (underline) or removed (line-through)
 *       <li> <tt>v5-up a</tt> - Same as previous attribute, but apply to &lt;a&gt; links
 *     </ul>
 * </blockquote>
 *
 * <h4 id="lookuptable">Version Lookup Table</h4>
 * <blockquote>
 *
 *     The global variable <tt>versionLookupTable</tt> holds a
 *     4-dimensional array to store which version ranges should be
 *     shown when, and in what style.  The array should be assigned
 *     values in the form of:
 *     <pre>
 *  versionLookupTable[<i>viewVersion</i>][<i>diffVersion</i>][<i>actionIndex</i>] = new Array(<i>a, b,...</i>)</pre>
 *
 *     <p>
 *     where <tt><i>actionIndex</i></tt> is 0, 1, 2, or 3 and <i>a, b,...</i>
 *     are indexes into the <tt>versionRanges</tt> array.
 *     The four values of <tt><i>actionIndex</i></tt> correspond to
 *     array indexes <tt><i>a, b,...</i></tt> as shown in the following table.
 *     In our example, since <tt>versionRanges</tt> has three elements,
 *     the new array assigned to <tt>versionLookupTable</tt> can have at
 *     most the three indexes (0, 1, 2).
 *     </p>
 *     <table style="border: thin #AAA solid;" cellpadding="5" cellspacing="0">
 *       <tr style="background-color: black; color: white;"><td align="center" width="1%"
 *               style="border: thin #AAA solid;" width="1%">
 *              <tt><b><i>action Index</i></b></tt> </td>
 *           <td align="center" width="1%"
 *               style="border: thin #AAA solid;" width="1%">
 *              <b>Meaning</b> </td>
 *           <td style="border: thin #AAA solid;">
 *              <tt><b><i>a, b,...</i></b></tt> </td> </tr>
 *
 *       <tr><td align="center" style="border: thin #AAA solid;">0</td>
 *           <td align="center" style="border: thin #AAA solid;">Show</td>
 *           <td align="left"   style="border: thin #AAA solid;">Indexes in <tt>versionRanges</tt> to show.</td></tr>
 *
 *       <tr><td align="center" style="border: thin #AAA solid;">1</td>
 *           <td align="center" style="border: thin #AAA solid;">Hide</td>
 *           <td align="left"   style="border: thin #AAA solid;">Indexes in <tt>versionRanges</tt> to hide.</td></tr>
 *
 *       <tr><td align="center" style="border: thin #AAA solid;">2</td>
 *           <td align="center" style="border: thin #AAA solid;">Add (underline)</td>
 *           <td align="left" style="border: thin #AAA solid;">Indexes in <tt>versionRanges</tt> that are in
 *              <tt>viewVersion</tt>, but not in <tt>diffVersion</tt>.
 *              This array should be empty when <tt>diffVersion</tt> is 0
 *              (a <tt>diffVersion</tt> of 0 means no diffs).</td></tr>
 *
 *       <tr><td align="center" style="border: thin #AAA solid;">3</td>
 *           <td align="center" style="border: thin #AAA solid;">Remove (line-through)</td>
 *           <td align="left" style="border: thin #AAA solid;">Indexes in <tt>versionRanges</tt> that are in
 *              <tt>diffVersion</tt>, but not in <tt>viewVersion</tt>.
 *              This array should be empty when <tt>diffVersion</tt> is 0
 *              (a <tt>diffVersion</tt> of 0 means no diffs).</td></tr>
 *     </table>
 *     <p>
 *     Example:
 *     </p>
 *     <pre>
 *       var versionLookupTable = new Array();
 *       var v = versionLookupTable;
 *
 *       // The following means when viewing v4 with no diffs, hide HTML
 *       // elements with <tt>v5-upShowHide</tt> class attributes
 *
 *       v[4] = new makeArray();
 *         v[4][0] = new makeArray();         // view 4 (no diffs)
 *         v[4][0][0] = new makeArray();      // (no elements to show)
 *         v[4][0][1] = new makeArray(0);     // hide class v5-upShowHide
 *         v[4][0][2] = new makeArray();      // (no elements to style as added)
 *         v[4][0][3] = new makeArray();      // (no elements to style as removed)
 *
 *       // The following means when viewing v5 with no diffs, show HTML
 *       // elements with <tt>v5-upShowHide</tt> class attributes
 *
 *       v[5] = new makeArray();
 *         v[5][0] = new makeArray();         // view 5 (no diffs)
 *         v[5][0][0] = new makeArray(0);     // show class v5-upShowHide
 *         v[5][0][1] = new makeArray();      // (no elements to hide)
 *         v[5][0][2] = new makeArray();      // (no elements to style as added)
 *         v[5][0][3] = new makeArray();      // (no elements to style as removed)
 *
 *         // The following means when viewing v5 diffed against v4, show HTML
 *         // elements with <tt>v5-upShowHide</tt> class attributes and display
 *         // elements with <tt>v5-up</tt> as added (with underline)
 *
 *         v[5][4] = new makeArray();         // view 5, diff 4
 *         v[5][4][0] = new makeArray(0);     // show class v5-upShowHide
 *         v[5][4][1] = new makeArray();      // (no elements to hide)
 *         v[5][4][2] = new makeArray(1, 2);  // style class 'v5-up' and 'v5-up a' as added
 *         v[5][4][3] = new makeArray();      // (no elements to style as removed) </pre>
 *     <p>
 *     <b>Function makeArray()</b> - The "makeArray()" function was added to
 *     workaround a JavaScript quirk for <tt>v[5][4][2] = new Array(2);</tt>,
 *     which creates an array of size 2, rather than the "expected" array of
 *     size 1 with whose element is 2.
 *     </p>
 *
 *     <p>
 *     <b>Class style definitions for content</b> - Also need to include
 *     a list of empty style definitions corresponding to the
 *     <a href="#versionranges"><tt>versionRanges</tt></a>
 *     table.  This is necessary to initialize these styles.
 *     </p>
 *
 *  <pre>
 *    &lt;style type="text/css" id="versioningStyles">
 *      .v5-upShowHide{}
 *      .v5-up{}
 *      .v5-up a{}
 *    &lt;/style&gt; </pre>
 *
 * </blockquote>
 *
 * <h4 id="classes">Class Attributes</h4>
 * <blockquote>
 *
 *     <p>
 *     Versioning uses class attributes in HTML elements to control how
 *     differences are shown or hidden, and if shown, marked as added
 *     (with underline) or removed (with line-through).  A "version range"
 *     class name appears as a class attribute in block and inline HTML
 *     tags, as shown:
 *     </p>
 *     <pre>
 *       &lt;li class="v3-v4ShowHide"&gt;
 *         &lt;span class="v3-v4"&gt;Description for v3 and v4 only&lt;/span&gt;
 *       &lt;/li&gt;
 *       &lt;li class="v5-upShowHide"&gt;
 *         &lt;span class="v5-up"&gt;Description for v5 and later&lt;/span&gt;
 *       &lt;/li&gt;</pre>
 *     <p>
 *     The above example causes the text "Description for v3 and v4 only." to
 *     appear only when in v3 or v4 view, but not when in v5 view.  When
 *     in v5 view, diffing against v4, this text will show underlined:
 *     "Description for v5 and later." and this text will show with
 *     line-through: "Description for v3 and v4 only."
 *     </p>
 *     See <a href="#htmlexamples">more HTML source examples</a>.
 *     </p>
 *     <p>
 *     <p>
 *     The following table lists the permissible class attributes
 *     where <tt>X</tt> and <tt>Y</tt> are integers and
 *     <tt>vX-vY</tt> is the version range.
 *     The first row has a class attribute for showing and hiding text.
 *     The second row has the main class attribute <tt>vX-vY</tt>;
 *     An element containing the class attribute <tt>vX-vY</tt>
 *     must enclose text to be versioned, and that element must be
 *     enclosed by <tt>vX-vYShowHide</tt>
 *     </p>
 *     <table border="1" cellpadding="5" cellspacing="0">
 *       <tr style="background-color: black; color: white;">
 *         <td><b>Class Attribute</b></td>
 *         <td><b>Purpose</b></td>
 *         <td><b>Sets CSS Property</b></td>
 *         <td><b>Where to Place Class Attribute</b></td>
 *       </tr>
 *       <tr>
 *         <td><tt>vX-vYShowHide</tt></td>
 *         <td>In any view, causes diff text to be shown or hidden
 *              (by setting <tt>display</tt> CSS property)</td>
 *         <td><tt>display: ""</tt> or <br />
 *             <tt>display: "none"</tt> </td>
 *         <td>Put in any block or inline elements, such &lt;div&gt;,
 *               &lt;p&gt;, &lt;tr&gt;, &lt;li&gt;, and &lt;span&gt;</td>
 *       </tr>
 *       <tr>
 *         <td><tt>vX-vY</tt></td>
 *         <td rowspan="1">When in a "diff" view, show text with underline or
 *             line-through (by setting <tt>text-decoration</tt> CSS property</td>
 *         <td nowrap><tt>text-decoration: underline<tt> or <br />
 *             <tt>text-decoration: line-through</tt> </td>
 *         <td>Put around text to be versioned</td>
 *       </tr>
 *       <tr>
 *         <td><tt>vX-vY a</tt></td>
 *         <td rowspan="1">Same as the previous attribute, but applies
 *             underline or line-through to override <tt>&lt;a&gt;</tt> link styles
 *             (typically blue link and purple visited colors)
 *         <td nowrap><tt>text-decoration: underline<tt> or <br />
 *             <tt>text-decoration: line-through</tt> </td>
 *         <td>Put around text to be versioned</td>
 *       </tr>
 *     </table>
 *     <p>
 *     where:
 *     </p>
 *     <ul>
 *       <tt>vX-vY</tt> is the version range <br />
 *       <tt>X</tt> and <tt>Y</tt> are integers where <tt>X</tt> &lt; <tt>Y</tt>, <br />
 *           with the special case that <tt>vY</tt> can have the value <tt>up</tt>,
 *           which means all versions later than <tt>vX</tt> <br />
 *       <tt>vX-vY</tt> must enclose any text to be versioned <br />
 *       A <tt>vX-vYShowHide</tt> class attribute must wrap <tt>vX-vY</tt> class attribute
 *     </ul>
 *
 *     Examples:
 *
 *     <pre>
 *     v2-v4                   // Text exists in versions 2, 3 and 4.
 *                                   When in diff view, apply underline or line-through
 *     v5-up                   // Text exists in versions 5 and up.
 *                                   When in diff view, apply underline or line-through
 *     v4-v5ShowHide           // Show text when viewing versions 4 and 5
 *     v5-upShowHide           // Show text when viewing versions 5 and later
 *     </pre>
 *
 *     <p>NOTE - Class attribute <tt>vX-vY</tt> is separate from the <tt>vX-vYShowHide</tt>
 *        class in order to improve JavaScript efficiency in setting styles.
 *     <p>
 *     <b>Adding classes to versionRange and versionLookupTable</b> -
 *     Whenever such class attribute names are used in HTML tags,
 *     the doc generator should add them to <tt>versionRanges</tt>
 *     and <tt>versionLookupTable</tt>.  Versions below <tt>versionFrom</tt>
 *     are "rounded up" to the <tt>versionFrom</tt> value.  So, in our
 *     example, <tt>v3-up</tt> would be added to <tt>versionRanges</tt>
 *     as <tt>v4-up</tt>.
 *     </p>
 *     <p>
 *     NOTE: Each document has exactly two version ranges that include all documented versions,
 *     from min to max versions -- in the example of generating docs from v2 to v5,
 *     these would be ranges "v2-v5" and "v2-up".  I believe these ranges do not appear
 *     in the lookup table because they have been optimized away -- text associated
 *     with these ranges will always appear, regardless which versions or diffs are
 *     being displayed.
 *     </p>
 * </blockquote>
 * <h4 id="versionlinks">Version Links</h4>
 * <blockquote>
 *
 *    <p>Finally, the script expects that there will be version links,
 *       diff links, and a "none" link (as shown at
 *       <a href="http://www.google.com/apis/adwords/developer/index.html">AdWords
 *       API Developer's Guide</a>):
 *    <ul>
 *      <li>a version link for each version, inclusive, between <tt>versionFrom</tt>
 *          and <tt>versionTo</tt> (using class rule <tt>.null</tt> when
 *          the class is not one of the versions being documented)
 *      <li>a diff link for each version, inclusive, between <tt>versionFrom</tt>
 *          and <tt>versionTo</tt> - 1 (using <tt>.null</tt> when the class
 *          attribute is not one of the versions being documented)
 *      <li>a link with class attribute <tt>.diffv0button</tt> for
 *          viewing no diffs.  This allows the user to explicitly
 *          switch from showing diffs to not showing diffs.
 *    </ul>
 *
 * <p id="htmlform">
 *     These links should have HTML in the form:<p>
 *  <pre>
 *    View:
 *    &lt;a class="v5button" href="javascript:showVersion(5);"&gt;V5&lt;/a&gt;
 *    &lt;a class="v4button" href="javascript:showVersion(4);"&gt;V4&lt;/a&gt;
 *
 *    Diff against:
 *    &lt;a class="diffv4button" href="javascript:diffCurrentVersion(4);"&gt;V4&lt;/a&gt;
 *    &lt;a class="diffv0button" href="javascript:diffCurrentVersion(0);"&gt;ONE&lt;/a&gt;</pre>
 *
 * <b>Class style definitions for versioning links</b> -
 *     Additionally, (possibly empty) styles for the version link
 *     class attributes must be defined in the following manner:
 *     The <tt>versionLinkStyles</tt> list goes from from v0 to
 *     <tt>versionTo</tt>; the <tt>diffLinkStyles</tt> goes from
 *     v0 to <tt>versionTo</tt> - 1.
 *     Note the use of placeholder classes <tt>.null</tt>. These are
 *     included so the style rules can be accessed by index for faster
 *     lookup. Note: The order of the style rules is important!</p>
 *
 *  <pre>
 *    &lt;style type="text/css" id="versionLinkStyles"&gt;
 *      .null{}           // placeholder for .v0button{}
 *      .null{}           // placeholder for .v1button{}
 *      .null{}           // placeholder for .v2button{}
 *      .null{}           // placeholder for .v3button{}
 *      .v4button{}
 *      .v5button{}
 *    &lt;/style&gt;
 *
 *    &lt;style type="text/css" id="diffLinkStyles"&gt;
 *      .diffv0button{}
 *      .null{}           // placeholder for .diffv1button{}
 *      .null{}           // placeholder for .diffv2button{}
 *      .null{}           // placeholder for .diffv3button{}
 *      .diffv4button{}
 *    &lt;/style&gt;</pre>
 *
 * </blockquote>
 * <h4 id="htmlexamples">HTML Source Examples</h4>
 * <blockquote>
 *     ShowHide in Paragraphs
 *     <pre>
 *       &lt;p class="v4-upShowHide"&gt;
 *           Some text in versions 4 and up.
 *           &lt;span class="v5-up"&gt;Description for versions 5 and up.&lt;/span&gt;
 *       &lt;/p&gt; </pre>
 *
 *     <pre>
 *       &lt;p class="v5-upShowHide v5-up"&gt;   // Both classes in the same element
 *           Description for version 5 and up.
 *       &lt;/p&gt; </pre>
 *
 *     ShowHide in Table Row
 *     <pre>
 *       &lt;tr class="v4-upShowHide"&gt;
 *           Description for versions 4 and up.
 *           &lt;span class="v5-up"&gt;Description for version 5 and up.&lt;/span&gt;
 *       &lt;/tr&gt; </pre>
 *
 *     ShowHide in List Item
 *     <pre>
 *       &lt;li class="v4-upShowHide"&gt;
 *           Description for versions 4 and up.
 *           &lt;span class="v5-up"&gt;Description for version 5 and up.&lt;/span&gt;
 *       &lt;/li&gt; </pre>
 *
 *     ShowHide in Span
 *     <pre>
 *       &lt;p class="v4-upShowHide"&gt;
 *           Description for versions 4 and up.
 *           &lt;span class="v5-upShowHide v5-up" Description for versions 5 and up.&lt;/span&gt;
 *       &lt;/p&gt;</pre>
 *
 *     <pre>
 *       &lt;p&gt;
 *           Description for all versions.
 *           &lt;span class="v5-upShowHide v5-up" Description for versions 5 and up.&lt;/span&gt;
 *       &lt;/p&gt;</pre>
 *
 *     <pre>
 *       &lt;p&gt;
 *           Description for all versions.
 *           &lt;span class="v4-v4ShowHide v4-v4" Description for v4-only text.&lt;/span&gt;
 *       &lt;/p&gt;  </pre>
 * </blockquote>
 */

var currentPageVersion_;

var CURRENT_VERSION_LINK_STYLE_ = {
  'textDecoration': 'none',
  'fontWeight': 'bold',
  'color': '#000'
};

var NON_CURRENT_VERSION_LINK_STYLE_ = {
  'textDecoration': '',
  'fontWeight': '',
  'color': ''
};
var SHOW_ACTION = 0;
var HIDE_ACTION = 1;
var ADD_ACTION = 2;
var REMOVE_ACTION = 3;


// Internally view 'All' version is mapped to number 999
var ALL_VERSIONNO = 999;
var versioningEnabled_ = false;
var versionRanges;
var versionLookupTable;
var isAllLinkActive = false;

/**
 * Initializes the version and diffs.  This is determined by the
 * useURIParameters parameter.<br/>
 * <br/>
 * Usage:<br />&nbsp; &nbsp;
 * <code>&lt;body onload="javascript:initializeVersioning(true);"&gt;</code>
 *
 * @param {boolean} useURIParameters If <tt>useURIParameters</tt> is true and
 *    the URI parameter 'v' exists, the initial view version
 *    will be its value.  Otherwise, it will default to the most
 *    recent version.  If <tt>useURIParameters</tt> is true and
 *    the URI parameter 'diff' exists, the diff version will be
 *    its value. Otherwise, it will default to no diffs.<br />
 *    <br/>
 *    Example:
 *    <pre>
 *    &lt;a href="page.html?v=5"&gt;
 *    &lt;a href="page.html?v=5&diff=4"&gt;
 *    </pre>
 */
function initializeVersioning(useURIParameters) {
  if (versionRanges === undefined || versionLookupTable === undefined) {
    return;
  } else {
    versioningEnabled_ = true;
  }

  // Added by shakila
  // Cookies store the previous version viewed, so that loaded doc version
  // will persist berween sessions
  var defaultPageVersion;
  var prev_version = readCookie(webserviceString + '_api_devguide_version');
  if (prev_version) {
    // If previously viewed version is out of the currently available version
    // range, then set selected version to newest version.
    if (prev_version < versionFrom || prev_version > versionTo) {
      defaultPageVersion = new PageVersion(versionTo, 0);
    } else {
      defaultPageVersion = new PageVersion(prev_version, 0);
    }
  } else {
    if (versionDefault < 0 || versionTo < versionDefault ) {
      defaultPageVersion = new PageVersion(versionTo, 0);
    } else {
      defaultPageVersion = new PageVersion(versionDefault, 0);
    }
  }

  // For "Open/Close all submenus" link, get its 'display' property
  // stored in a cookie named 'apiref_display_status'
  readCookieToSetElementsDisplay();

  // Get the version to show from the URI if useURIParameters is true.
  var useDefaults;
  if (useURIParameters) {
    var pageVersion = getVersionFromURI(defaultPageVersion);
    // set drop down menu option to page view version
    changeVersionTo(pageVersion);
    if (pageVersion.viewVersion == ALL_VERSIONNO) {
      showAllVersions();
    } else {
      var showResult =
          showVersion(pageVersion.viewVersion, pageVersion.diffVersion);
      if (showResult === undefined) {
        useDefaults = false;
      } else {
        useDefaults = true;
        currentPageVersion_ = undefined;
      }
    }
  } else {  // Default to showing the most recent version without diffs
    useDefaults = true;
  }

  if (useDefaults) {
    // set drop down menu option to default version
    changeVersionTo(defaultPageVersion);
    showVersion(defaultPageVersion.viewVersion, defaultPageVersion.diffVersion);
  }
}

// Added by shakila
function createCookie(keyName, keyValue, noOfDays) {
  if (noOfDays) {
    var date = new Date();
    date.setTime(date.getTime() + (noOfDays * 24 * 60 * 60 *1000));
    var expires = '; expires=' + date.toGMTString();
  } else {
    var expires = '';
  }
  document.cookie = keyName + "=" + keyValue + expires + "; path=/";
}

function readCookie(keyName) {
  var start = document.cookie.indexOf(keyName + "=");
  var len = start + keyName.length + 1;
  if (!start && keyName != document.cookie.substring(0, keyName.length)) {
    return null;
  }
  if (start == -1) {
    return null;
  }
  var end = document.cookie.indexOf(";", len);
  if (end == -1) {
    end = document.cookie.length;
  }
  return unescape(document.cookie.substring(len, end));
}

/**
 * If the URI parameter 'version' exists, the initial view version will be its
 * value. Otherwise, it will default to the most recent version. If the URI
 * parameter 'diff' exists, the diff version will be that value. Otherwise, it
 * will default to no diffs.
 *
 * @private
 *
 * @param defaultPageVersion  The page version to default to.
 */
function getVersionFromURI(defaultPageVersion) {
  var pageVersion = new PageVersion(defaultPageVersion.viewVersion,
                                    defaultPageVersion.diffVersion);
  var invalidView = false;
  var invalidDiff = false;

  if (location.search.length > 1) {
    var nameValuePairs = location.search.substring(1).split('&');
    for (var onPair = 0; onPair < nameValuePairs.length; ++onPair) {
      var nameValue = nameValuePairs[onPair].split('=');
      if (nameValue.length == 2 && nameValue[0] !== '' && nameValue[1] !== '') {
        var paramName = nameValue[0];
        var paramValue = nameValue[1];

        if (paramName == 'v') {
          if (paramValue == "all") {
            pageVersion.viewVersion = ALL_VERSIONNO;
          } else if (paramValue < versionFrom || paramValue > versionTo) {
            invalidView = true;
          } else {
            pageVersion.viewVersion = paramValue;
          }
        } else if (paramName == 'diff') {
          if (paramValue > 0 &&
              (pageVersion.viewVersion == ALL_VERSIONNO ||
              paramValue >= pageVersion.viewVersion ||
              paramValue < versionFrom ||
              !isValidDiffVersion_(paramValue))) {
            invalidDiff = true;
          } else {
            pageVersion.diffVersion = paramValue;
          }
        }
      }
    } // End of 'for' loop
  }

  // display alert message when requested view or diff version is invalid
  var versionAlert = document.getElementById("version-alert");
  var diffAlert = document.getElementById("diff-alert");
  if (versionAlert && diffAlert) {
    versionAlert.style.display = 'none';
    diffAlert.style.display = 'none';
  }
  if (invalidView && versionAlert) {
    versionAlert.style.display = 'inline';
  } else if (invalidDiff && diffAlert) {
    diffAlert.style.display = 'inline';
  }

  return pageVersion;
}

/**
 * Checks if paramValue is an available diff selection in the drop-down menu.
 *
 * @param paramValue {int} input version to be checked if it is a valid
 *    diff version
 * @return True iff paramValue is an available diff selection in the drop-down
 *    menu.
 *
 */

function isValidDiffVersion_(paramValue) {
  var versionSelect = document.getElementById("version-select");
  if (!versionSelect) {
    return false;
  }
  for (var i = 0; i < versionSelect.options.length; i++) {
    var currentValue = versionSelect.options[i].value;
    if (currentValue.indexOf("diff") != -1) {
      var versions = currentValue.split('-');
      var viewVersion = versions[1];
      var diffVersion = versions[2];
      if (diffVersion == paramValue) {
        return true;
      }
    }
  }
  return false;
}

/**
 * Used to show versions or to show difference between versions when any option
 * in version drop down is selected
 */
function changeVersion() {
  var selectElement = document.getElementById("version-select");
  if (!selectElement) {
    return;
  }
  var selectedValue = selectElement.options[selectElement.selectedIndex].value;
  if (!selectedValue) {
    return;
  }
  if (selectedValue.indexOf("all") != -1) {
    showAllVersions();
  } else if (selectedValue.indexOf("diff") != -1) {
    var versions = selectedValue.split('-');
    var viewVersion = versions[1];
    var diffVersion = versions[2];
    showVersion(viewVersion, diffVersion);
  } else {
    showVersion(selectedValue);
  }
}

/**
 * To show content of the input version
 *
 * @private
 * @param {Object} pageVersion The <a href="PageVersion.html">page version</a>
 *                             that is previously viewed.
 */
function changeVersionTo(pageVersion) {
  var versionSelect = document.getElementById("version-select");
  if (!versionSelect || !pageVersion) {
    return;
  }

  var newOptionValue = "";
  if (pageVersion.diffVersion == 0 &&
      pageVersion.viewVersion == ALL_VERSIONNO) {
    newOptionValue = "all";
  } else if (pageVersion.diffVersion == 0) {
    newOptionValue = pageVersion.viewVersion;
  } else {
    newOptionValue = "diff-" + pageVersion.viewVersion +
                     "-" + pageVersion.diffVersion;
  }
  // If new option value is same as currently selected value, then don't
  // loop through select options.
  if (newOptionValue == 
      versionSelect.options[versionSelect.selectedIndex].value) {
    return;
  }
  for (var i = 0, curOption; curOption = versionSelect.options[i]; i++) {
    if (curOption.value == newOptionValue) {
      versionSelect.selectedIndex = curOption.index;
      return;
    }
  }
}

/**
 * Shows version 'viewVersion' and diffs it against 'opt_diffVersion'.
 * Differences are shown with line-through to indicate that something has
 * been removed in the newer version, and with an underline and green to
 * indicate that something has added in the newer version.<br />
 * <br />
 * Usage:
 * <ul>
 *  <li>To show version 5 with no diffs:
 *    <code>&lt;a href="" onclick="javascript:showVersion(5, 0);"&gt;
 *    Show V5&lt;/a&  gt;</code>
 *  </li>
 *   <li>The same command, using the default 'opt_diffVersion' of 0:<br />
 *   <code>&lt;a href="" onclick="javascript:showVersion(5);"&gt;
 *   Show V5&lt;/a&gt;</code>
 *   </li>
 *   <li>To diff version 5 against version 4:<br />
 *   <code>&lt;a href="" onclick="javascript:showVersion(5, 4);"&gt;
 *   Diff V5 against V4&lt;/a&gt;</code>
 *   </li>
 * </ul>
 *
 * @param {int} viewVersion      The version to show, an integer.
 * @param {int} opt_diffVersion  The version to diff against, an integer.
 *                               Defaults to 0, which means no diffs
 *
 * @return undefined if successful, false otherwise.
 * @type boolean
 */
function showVersion(viewVersion, opt_diffVersion) {
  if (!versioningEnabled_) {
    return false;
  }

  // Default opt_diffVersion to 0.
  if (opt_diffVersion === undefined) {
    opt_diffVersion = 0;
  }
  // Added by shakila
  createCookie(webserviceString + '_api_devguide_version', viewVersion, 365);
  var pageTitle = document.getElementById('page_title');

  if (pageTitle != null && pageTitle != "" && pageTitle != 'undefined') {
    var Title = document.getElementById('doc_title_text');
    var docTitle = Title.firstChild.nodeValue;
    if (docTitle) {
      document.title = 
          pageTitle.firstChild.nodeValue + " - V" + viewVersion +
          " (" + docTitle + ")";
    } else {
      document.title = pageTitle.firstChild.nodeValue + " - V" + viewVersion;
    }
  } else {
    if (pageTitle == null || pageTitle == 'undefined') {
      pageTitle=document.getElementById('page_title_v' + viewVersion);
      if (pageTitle != null && pageTitle != "" && pageTitle != 'undefined') {
        document.title=pageTitle.firstChild.nodeValue;
      }
    }
  }

  var previousPageVersion = currentPageVersion_;
  currentPageVersion_ = new PageVersion(viewVersion, opt_diffVersion);

  // Ensures that the version is valid.
  if (!currentPageVersion_.validate()) {
    return false;
  }

  if (previousPageVersion !== undefined) {
    // If viewing the same version again, don't need to do any work.
    // Otherwise, if the previous version had diffs, undo them.
    if (previousPageVersion.viewVersion == currentPageVersion_.viewVersion &&
        previousPageVersion.diffVersion == currentPageVersion_.diffVersion &&
        !isAllLinkActive) {
      return;
    } else if (previousPageVersion.diffVersion > 0) {
      undoStyleDiffs(previousPageVersion);
    }
  }

  if (isAllLinkActive) {
    isAllLinkActive = false;
  }

  // Finally apply the styles!
  styleVersions(currentPageVersion_);
  // Styling version links aren't needed for drop down menu
  if (document.getElementById('versionLinkStyles') ||
      document.getElementById('diffLinkStyles')) {
    styleVersioningLinks(previousPageVersion, currentPageVersion_);
  }
  styleSeeSections();
  // Everything has completed, so return successfully.
  return;
}

/**
 * Shows contents of all versions when "All" version link is clicked.
 * Currently it is invoked by releasenotes.html page.
 */
function showAllVersions() {
  var previousPageVersion = currentPageVersion_;
  var styleElement = document.getElementById('versioningStyles');
  var styles = (styleElement.sheet) ?
      styleElement.sheet : styleElement.styleSheet;
  // 'styleSheet' property is not avaiable for LINK/STYLE element in Safari,
  // so use 'document.styleSheet' to get the particular style sheet object from
  // style sheet collection
  if (!styles) {
    styles = getStyleSheetElementForStyle(styleElement);
  }
  var rules = (styles.cssRules) ? styles.cssRules : styles.rules;
  for (var i = 0; i < rules.length; i++) {
    // Show contents of all versions
    setStyleForStylesheetIdAndRuleIndex('versioningStyles', i, {'display': ''});
  }

  styleElement = document.getElementById('versionLinkStyles');
  if (!styleElement) {
    return;
  }
  styles = (styleElement.sheet) ? styleElement.sheet : styleElement.styleSheet;
  if (!styles) {
    styles = getStyleSheetElementForStyle(styleElement);
  }
  rules = (styles.cssRules) ? styles.cssRules : styles.rules;
  for (var i = 0; i < rules.length; i++) {
    // Highlight "All" version link
    if (rules[i].selectorText == '.allbutton') {
      setStyleForStylesheetIdAndRuleIndex(
          'versionLinkStyles', i, CURRENT_VERSION_LINK_STYLE_);
      isAllLinkActive = true;
    }
  }
  // Dim the previous version link
  if (isAllLinkActive && previousPageVersion !== undefined) {
    setStyleForStylesheetIdAndRuleIndex('versionLinkStyles',
        previousPageVersion.viewVersion, NON_CURRENT_VERSION_LINK_STYLE_);
  }
  // Hide the diff links
  if (document.getElementById('diffLinks')) {
    document.getElementById('diffLinks').style.display = 'none';
  }
}

/**
 * Page version class attribute used to store the view and diff versions.
 *
 * @private
 * @constructor
 *
 * @param {int} viewVersion  The page version to view, an integer.
 * @param {int} diffVerison  The page version to diff against, an integer.
 */
function PageVersion(viewVersion, diffVersion) {
  this.viewVersion = viewVersion;
  this.diffVersion = diffVersion;
}

/**
 * Validate the 'viewVersion' and 'diffVersion'
 *
 * @private
 * @member PageVersion
 * @return True if the versions are valid, and false otherwise.
 */
PageVersion.prototype.validate = function () {
  // Ensures that 'viewVersion' and 'diffVersion' are numbers
  if (isNaN(this.viewVersion) || isNaN(this.diffVersion)) {
    return false;
  }

  // Ensures that 'viewVersion' and 'diffVersion' are between 
  // 'wsdlVersionFrom' and 'wsdlVersionTo' (which are set in
  // initializeVersioning().
  if (this.viewVersion < wsdlVersionFrom ||
      this.viewVersion > wsdlVersionTo ||
     (this.diffVersion < wsdlVersionFrom && this.diffVersion > 0) ||
      this.diffVersion > wsdlVersionTo ||
      this.diffVersion > this.viewVersion) {
    return false;
  }

  // If 'diffVersion' is equal to 'viewVersion', don't do diffs.
  if (this.diffVersion == this.viewVersion) {
    this.diffVersion = 0;
  }

  return true;
}

/**
 * Apply the styles in the global
 * <a href="overview-summary.html#lookuptable">version lookup table</a>
 * at the index composed of pageVersion, iterating from
 * <tt>actionStart</tt> to <tt>actionEnd</tt> (which are between 0 and 3).
 * If undo is true,
 * <a href="#!s!getStylesForActionAndDescriptor">
 * getStylesForActionAndDescriptor</a>
 * is called with a negated value.
 *
 * @private
 *
 * @param pageVersion  The <a href="PageVersion.html">page version</a>
 *                     that is currently being viewed.
 * @param actionStart  The index of the first action in the
 *                     <a href="overview-summary.html#lookuptable">version
 *                     lookup table</a> to iterate over.
 * @param actionEnd    The index of the last action in the
 *                     <a href="overview-summary.html#lookuptable">version
 *                     lookup table</a> to iterate over.
 * @param undo         Whether or not the actions are undo actions.
 *
 * @see PageVersion
 */
function applyLookupStyles(pageVersion, actionStart, actionEnd, undo) {
  // Ensure that the lookup table has the expected structure
  var vlt = versionLookupTable[pageVersion.viewVersion]
  if (vlt === undefined || vlt[pageVersion.diffVersion] === undefined) {
    return;
  }

  var lookup =
    versionLookupTable[pageVersion.viewVersion][pageVersion.diffVersion];

  // Style the designated class attributes
  for (var action = actionStart; action <= actionEnd; ++action) {
    for (var j = 0; j < lookup[action].length; ++j) {
      var versionRangeIndex = lookup[action][j];

      try {
        // Undo-actions are the negative of their actions
        // Ex: undo-added (-2), added (2)
        var styles = getStylesForActionAndDescriptor(
            (undo ? undoAction(action) : action),
            versionRanges[versionRangeIndex][1]);

        setStyleForStylesheetIdAndRuleIndex('versioningStyles',
                                            versionRangeIndex,
                                            styles);
        // Get from version number from the version range element
        // For example, get '4' from version range element {'v4-up',''}
        var versionno = 
            versionRanges[versionRangeIndex][0].split('-')[0].substring(1);
        setStyleForNewInVersionString(versionno, action);

      } catch(exception) {
        // Continue with the script - the user shouldn't see an error message.
      }
    }
  }
}

function undoAction(action) {
  return -1 * action;
}

/**
 * Sets the style for headers of "See" section based on its links.
 *
 */
function styleSeeSections() {
  var seeSections = document.getElementsByName('seesection');
  for (var i = 0; i < seeSections.length; i++) {
    var seeLinks = seeSections[i].getElementsByTagName('span');
    var hiddenLinksCnt = 0;
    for (var j = 0; j < seeLinks.length; j++) {
      var properties = getStyleForStylesheetIdAndRule('versioningStyles',
                                                      seeLinks[j].className);
      if (properties && properties.getPropertyValue('display') == 'none') {
        ++hiddenLinksCnt;
      }
    }
    seeSections[i].style.display = 
      (hiddenLinksCnt == seeLinks.length) ? 'none' : '';
  }
}

/**
 * Returns an array of style objects for the rule <tt>ruleName</tt> present
 * in the stylesheet with id <tt>stylesheetId</tt>.
 *
 * @private
 *
 * @param stylesheetId  The id HTML attribute of the stylesheet.
 * @param ruleName      The name of the rule in the stylesheet, whose styles are
 * to be returned.
 */
function getStyleForStylesheetIdAndRule(stylesheetId, ruleName) {
  var stylesheet = document.getElementById(stylesheetId);
  var styles = (stylesheet.sheet) ? stylesheet.sheet : stylesheet.styleSheet;
  if (!styles) {
    styles = getStyleSheetElementForStyle(stylesheet);
  }
  // Get the rules
  var rules = (styles.cssRules) ? styles.cssRules : styles.rules;
  if (rules) {
    for (var j = 0; j < rules.length; j++) {
      var currentRuleName = rules[j].selectorText.substring(1);
      if (currentRuleName == ruleName) {
        return rules[j].style;
      }
    }
  }
  return null;
}

/**
 * Sets style for "new in v(x)" string based on action parameter
 *
 * @private
 *
 * @param versionno version number present in "new in v(x)" string
 *                  Here x represents the version number
 * @param action Action can be any of the following:
 *               <ul>
 *                  <li> 0 - Show
 *                  <li> 1 - Hide
 *                  <li> 2 - Added
 *                  <li> 3 - Removed
 *               </ul>
 */
function setStyleForNewInVersionString(versionno, action) {
  // Looks for newInVx class in the style element 'newMemberStyle' and
  // Sets its display property to show or hide based on the action.
  var styleElement = document.getElementById('newMemberStyle');
  var styles = (styleElement.sheet) ? styleElement.sheet : styleElement.styleSheet;
  if (!styles) {
    styles = getStyleSheetElementForStyle(styleElement);
  }
  var rules = (styles.cssRules) ? styles.cssRules : styles.rules;
  for (var i = 0; i < rules.length; i++) {
    var cssRule = rules[i].selectorText;
    // If the style contains newInVx class then change the display property
    if (cssRule.indexOf('newInV' + versionno) != -1) {
      if (action == '2') {
        // show "new in v(x)" string for added elements
        setStyleForStylesheetIdAndRuleIndex(
            'newMemberStyle', i, {'display': ''});
      } else {
        // hide "new in v(x)" string for other elements
        setStyleForStylesheetIdAndRuleIndex(
            'newMemberStyle', i, {'display': 'none'});
      }
    }
  }
}

/**
 * Calls <tt><a href="#!s!applyLookupStyles">applyLookupStyles</a></tt>
 * to undo diffs.
 *
 * @private
 *
 * @param pageVersion  The page version to use in the lookup table.
 */
function undoStyleDiffs(pageVersion) {
  applyLookupStyles(pageVersion, 2, 3, true);
}

/**
 * Calls <tt><a href="#!s!applyLookupStyles">applyLookupStyles</a></tt>
 * to show and hide elements, as well as style added and removed ones.
 *
 * @private
 *
 * @param pageVersion  The page version to use in the lookup table.
 */
function styleVersions(pageVersion) {
  applyLookupStyles(pageVersion, 0, 3, false);
}

/**
 * Returns an associative list of CSS style property:value pairs
 * for a given action-descriptor pair.
 * For example, passing in <tt>0</tt> (meaning "show") and
 * <tt>ShowHide</tt> returns <tt>{'display':'block'}</tt>,
 * which causes the block of text to be shown.
 * <p>
 * Undo-actions are the negative of their actions.<br>
 * For example, 2 means "added" and -2 means "undo-added".
 * Therefore, passing in <tt>-2</tt> and <tt>""</tt> for descriptor
 * returns <tt>{'display':'block'}</tt>, which causes the green
 * underline to be undone.
 *
 * @private
 *
 * @param action      The action index:
 *                    <tt>0</tt> (show), <tt>1</tt> (hide),
 *                    <tt>2</tt> (add) or <tt>3</tt> (remove)
 * @param descriptor  The descriptor: <tt>ShowHide</tt>
 */

function getStylesForActionAndDescriptor(action, descriptor) {
  switch (action) {
    case SHOW_ACTION:
      if (descriptor == 'ShowHide') {
        return {'display': ''};
      } else {
        throw 'InvalidDescription';
      }
      break;

    case HIDE_ACTION:
      return {'display': 'none'};

    case ADD_ACTION:
      return {
        'color': '#060',
        'textDecoration': 'underline'
      };

    case undoAction(ADD_ACTION):
      return {
        'color': '',
        'textDecoration': ''
      };

    case REMOVE_ACTION:
      return {'textDecoration': 'line-through'};

    case undoAction(REMOVE_ACTION):
      return {'textDecoration': ''};

    default:
      throw 'InvalidAction';
  }
}

/**
 * Applies styling to the versioning links.
 * These links have class attribute names v1button, v2button, etc.
 * and typically have visible link labels such as "V1", "V2", etc.
 *
 * @param {int} previousPageVersion  an integer
 * @param {int} currentPageVersion  an integer
 */
function styleVersioningLinks(previousPageVersion, currentPageVersion) {
  if (previousPageVersion !== undefined) {
    setStyleForStylesheetIdAndRuleIndex('versionLinkStyles',
                                        previousPageVersion.viewVersion,
                                        NON_CURRENT_VERSION_LINK_STYLE_);
  }
  setStyleForStylesheetIdAndRuleIndex('versionLinkStyles',
                                      currentPageVersion.viewVersion,
                                      CURRENT_VERSION_LINK_STYLE_);
  // Style the diff links if they have changed
  if (previousPageVersion !== undefined &&
      previousPageVersion.diffVersion != currentPageVersion.diffVersion) {
    setStyleForStylesheetIdAndRuleIndex('diffLinkStyles',
                                        previousPageVersion.diffVersion,
                                        NON_CURRENT_VERSION_LINK_STYLE_);
  }
  if (previousPageVersion === undefined || (previousPageVersion !== undefined &&
      previousPageVersion.diffVersion != currentPageVersion.diffVersion)) {
    setStyleForStylesheetIdAndRuleIndex('diffLinkStyles',
                                        currentPageVersion.diffVersion,
                                        CURRENT_VERSION_LINK_STYLE_);
  }

  // Hide the diff links when viewing the lowest version.
  // Otherwise, hide all the diff links whose versions >= the current version.
  if (currentPageVersion.viewVersion == versionFrom) {
    document.getElementById('diffLinks').style.display = 'none';
  } else {
    document.getElementById('diffLinks').style.display = 'block';
    // Add right padding so diff links align with the version links
    document.getElementById('diffLinks').style.paddingRight = '7px';
    for (var version = versionFrom; 
        version <= versionTo && version < wsdlVersionTo;
        version++) {
      if (version >= currentPageVersion.viewVersion) {
        setStyleForStylesheetIdAndRuleIndex('diffLinkStyles',
                                            version,
                                            {'display': 'none'});
      } else {
        setStyleForStylesheetIdAndRuleIndex('diffLinkStyles',
                                            version,
                                            {'display': 'inline'});
      }
    }
  }

  // Dim "All" version link (if present).  "All" version link is highlighted 
  // only when it is clicked.
  var styleElement = document.getElementById('versionLinkStyles');
  var styles = 
      (styleElement.sheet) ? styleElement.sheet : styleElement.styleSheet;
  if (!styles) {
    styles = getStyleSheetElementForStyle(styleElement);
  }
  var rules = (styles.cssRules) ? styles.cssRules : styles.rules;
  for (var i = 0; i < rules.length; i++) {
    if (rules[i].selectorText == '.allbutton') {
      setStyleForStylesheetIdAndRuleIndex('versionLinkStyles',
            i, NON_CURRENT_VERSION_LINK_STYLE_);
    }
  }
}

/**
 * Sets the styles specified in <tt>styles</tt> for the rule whose
 * index is <tt>ruleIndex</tt> in the stylesheet with id
 * <tt>stylesheetId</tt>.
 * <p>
 * For example, given this style definition:
 * <pre>
 * &lt;style type="text/css" id="versioningStyles"&gt;
 *   .v5-upShowHide{}
 *   .v5-up{}
 *   .v5-up a{}
 * &lt;/style text="type/css"&gt;
 * </pre>
 * This style has a stylesheetId "versioningStyles" and
 * contains three rules with ruleIndex 0, 1 and 2.
 * To toggle the first style so that its display is off, you would pass in:
 * <pre>
 * setStyleForStylesheetIdAndRuleIndex('versioningStyles', 0, {'display':'none'});
 * </pre>
 *
 * @param stylesheetId  The id of the stylesheet.
 * @param ruleIndex     The index of the css rule in the stylesheet.
 * @param styles        An array of style/value pairs, such as
 *                      <tt>{'fontWeight':'bold', 'color':'black'}</tt><br>
 *                      Note: Hyphenated properties change to camel-case.
 *                      (Example: <tt>font-weight</tt> becomes <tt>fontWeight</tt>)
 */
function setStyleForStylesheetIdAndRuleIndex(stylesheetId, ruleIndex, styles) {
  var myStyle =
    getStyleForStylesheetIdAndRuleIndex(stylesheetId, ruleIndex);
  if (myStyle) {
    for (var property in styles) {
      myStyle[property] = styles[property];
    }
  }
}

/**
 * Gets an array of style objects for the rule index of value
 * <tt>ruleIndex</tt> in the stylesheet with id <tt>stylesheetId</tt>.
 * The rule index is a designed to be the same as the index of the
 * class attributes in <a href="#versionranges">versionRanges</a>.
 * For example, let's say <tt>ruleIndex</tt> is 0.  This indexes
 * into the first element of the rule array, something like
 * <tt>v5-upShowHide</tt> -- this function returns the style
 * object of that name.
 *
 * @private
 *
 * @param stylesheetId  The id HTML attribute of the stylesheet.
 * @param ruleIndex     The index of the rule in the stylesheet to get.
 */
function getStyleForStylesheetIdAndRuleIndex(stylesheetId, ruleIndex) {
  var stylesheet = document.getElementById(stylesheetId);
  var styles = (stylesheet.sheet) ? stylesheet.sheet : stylesheet.styleSheet;
  if (!styles) {
    styles = getStyleSheetElementForStyle(stylesheet);
  }
  // Get the rules based on the browser.
  // Mozilla uses 'cssRules', IE uses 'rules'.
  var rules = (styles.cssRules) ? styles.cssRules : styles.rules;

  return rules[ruleIndex].style;
}

/**
 * Calls the <tt>showVersion</tt> function. Same as calling
 * <tt>showVersion(X, Y)</tt>, where <tt>X</tt> is the version currently
 * being viewed, and <tt>Y</tt> is <tt>diffVersion</tt>.<br />
 * This method simplifies the HTML to be attached to the diff button.
 * <br />
 * Usage:<br />&nbsp; &nbsp;
 * <code>&lt;a href="" onclick="javascript:diffCurrentVersion(4);"&gt;
 *   Diff current version against V4&lt;/a&gt;</code>
 *
 * @param {int} diffVersion  The version to diff against, an integer.
 *
 * @return True if succeeded, false otherwise.
 * @type boolean
 */
function diffCurrentVersion(diffVersion) {
  if (!versioningEnabled_) {
    return false;
  }

  return showVersion(currentPageVersion_.viewVersion, diffVersion);
}

/**
 * A function similar to constructor Array() but when passed a single
 * integer x will create an array with one element of value.
 * (In this case, Array() returns an array with x undefined elements.)
 * This works around the following quirk in JavaScript:
 * <pre>
 * v = new Array(5,6,7)    // creates 3 elements [5,6,7]
 * v = new Array(5,6)      // creates 2 elements [5,6]
 * v = new Array(5)        // creates 5 undefined elements [ , , , , ]
 * </pre>
 * That is, when initializing an array, if you pass in more than one
 * element, such as <tt>new Array(3, 4)</tt>, that creates an array
 * with values 3 and 4.  But passing in only one element <tt>new Array(3)</tt>
 * creates an array of length 3, not value 3, length 1.
 */
function makeArray() {
  if (arguments.length == 1) {
    return [arguments[0]];
  } else {
    return Array.apply(null, arguments);
  }
}

/**
 * A function to toggle the display of request rows with cost of "1" API Unit.
 * Used only in adwords_api_ratesheet.html page
 */
function toggleCostDisplay() {
  var styleElement = document.getElementById('CostOneStyle');
  var styles =
      (styleElement.sheet) ? styleElement.sheet : styleElement.styleSheet;
  if (!styles) {
    styles = getStyleSheetElementForStyle(styleElement);
  }
  var rules = (styles.cssRules) ? styles.cssRules : styles.rules;

  // Toggle the style for class="costone" elements
  for (var i = 0; i < rules.length; i++) {
    if (rules[i].selectorText == '.costone') {
      if (rules[i].style.display == '') {
        rules[i].style.display = 'none';
      } else if (rules[i].style.display == 'none') {
        rules[i].style.display = '';
      }
    }
  }

  // Show/hide an entire <tbody/> element if all requests cost 1 unit
  var hiddenVersionStyles = getHiddenVersioningStyles_();
  var tbodyElements = document.getElementsByTagName("tbody");
  for (var i = 0; i < tbodyElements.length; i++) {
    var rowCount = tbodyElements[i].rows.length;
    var costoneCount = 0;

    // Skip past the table header
    if (rowCount == 1) {
      continue;
    }

    // Count the costone elements in the current <tbody/>
    for (var j = 0; j < rowCount; j++) {
      var classNames = tbodyElements[i].rows[j].className;
      if (classNames.indexOf('costone') != -1) {
        costoneCount = costoneCount + 1;
      } else {
        if (hiddenVersionStyles) {
          for (var k = 0; k < hiddenVersionStyles.length; k++) {
            if (classNames.indexOf(hiddenVersionStyles[k]) != -1) {
              costoneCount = costoneCount + 1;
              break;
            }
          }
        }
      }
    }

    // Toggle the entire tbody element
    if ((costoneCount + 1) == rowCount) {
      if (tbodyElements[i].style.display == '') {
        tbodyElements[i].style.display = 'none';
      } else if (tbodyElements[i].style.display == 'none') {
        tbodyElements[i].style.display = '';
      }
    }
  }
}

/**
 * Returns an array containing the names of CSS rules used to implement 
 * versioning and that are currently set to be hidden.
 *
 * @return array of CSS rules that are set to be hidden.
 */
function getHiddenVersioningStyles_() {
  var hiddenVersionStyles = new Array();
  var styleElement = document.getElementById('versioningStyles');
  if (!styleElement) {
    return hiddenVersionStyles;
  }

  var styles =
      (styleElement.sheet) ? styleElement.sheet : styleElement.styleSheet;
  if (!styles) {
    styles = getStyleSheetElementForStyle(styleElement);
  }
  var rules = (styles.cssRules) ? styles.cssRules : styles.rules;
  // Loop through all versioning styles of form "v(x)-v(y)ShowHide" or
  // "v(x)-upShowHide" and find out the ones that are set to be hidden
  for (var i = 0; i < rules.length; i++) {
    var ruleName = rules[i].selectorText.substr(1);
    if (ruleName.indexOf("ShowHide") != -1 &&
        rules[i].style.display == 'none') {
      hiddenVersionStyles.push(ruleName);
    }
  }

  return hiddenVersionStyles;
}

/**
 * Toggles the display of all data objects present under each service
 * of left side nav. Also toggles other submenus present in the
 * left side nav bar. Currently used only for adwords
 */
function toggleAllSubMenus() {
  var displayStatus;
  var dataobjectElement;
  var showElement = document.getElementById('show_all_submenus');
  if (showElement) {
    // Change the 'display' property of all submenus based on
    // which of the following text is shown  either
    // "Close all submenus" or "Open all submenus"
    if (showElement.style.display == 'none') {
      displayStatus = 'hide';
    } else if (showElement.style.display == 'block') {
      displayStatus = 'show';
    }
    var apiRefSubMenu = document.getElementById('firstlevel_item1_submenu');
    if (apiRefSubMenu) {
      for (var i = 0; i < apiRefSubMenu.childNodes.length; i++) {
        var currentChild = apiRefSubMenu.childNodes[i];
        if (currentChild && currentChild.className == 'expandable') {
          storeIntoCookie(currentChild.id, displayStatus);
          showHideSubMenuOfElementId(currentChild.id, displayStatus);
          showHideImageOfElementId(currentChild.id, displayStatus);
        }
      }
    } // end of 'if' for 'apiRefSubMenu'
    // Change the text in link to one of the following
    // "Close all submenus" or "Open all submenus"
    toggleDisplayTextAndImage(displayStatus);
    // store the value of 'display' property to 'apiref_display_status'
    // cookie
    createCookie(webserviceString + '_apiref_display_status', displayStatus, 
        365);
   }
}

/**
 * Sets the display property of each element based on
 * the cookie value.
 */
function readCookieToSetElementsDisplay() {
  var displayStatus;
  var sideNavElement = document.getElementById('sidenav');

  if (sideNavElement) {
    var listElements = sideNavElement.getElementsByTagName('LI');
    if (listElements) {
      var toggleAllSubMenu = document.getElementById('toggle_all_submenus');
      var linkElementParent =
          (toggleAllSubMenu)? toggleAllSubMenu.parentNode : null;
      for (var i = 0; i < listElements.length; i++) {
        var listElement = listElements[i];
        // If the element has a sub menu associated with it, then toggle
        // its sub menu based on the display value stored in the cookie
        if (listElement.className == 'expandable') {
          var listElementDisplay = getDisplayStatusFromCookie(listElement.id);
          showHideSubMenuOfElementId(listElement.id, listElementDisplay);
          showHideImageOfElementId(listElement.id, listElementDisplay);
          // Handle the case, when 'LI'element has a 'Open/Close all submenus'link
          if (linkElementParent != null &&
              listElement.id == linkElementParent.id) {
            showHideToggleAllSubMenusLink(listElementDisplay);
            if (listElementDisplay == 'show') {
              var childSubmenu =
                  document.getElementById(listElement.id + '_submenu');
              readCookietoSetServiceElementsDisplay(childSubmenu);
            }
          }
        }
      }
    }
  }
}

/**
 * Sets the display property of each service element
 * based on the cookie value.
 */
function readCookietoSetServiceElementsDisplay(element) {
  var displayStatus;
  var cookieValue = '';
  cookieValue = readCookie(webserviceString + "_apiref_display_status");
  if (element) {
    for (var i = 0; i < element.childNodes.length; i++) {
      var currentChild = element.childNodes[i];
      if (currentChild && currentChild.className == 'expandable') {
        var serviceDisplay = getDisplayStatusFromCookie(currentChild.id);
        if (serviceDisplay == 'notfound' || serviceDisplay == cookieValue) {
          displayStatus = cookieValue;
        } else {
          displayStatus = serviceDisplay;
        }
        showHideSubMenuOfElementId(currentChild.id, displayStatus);
        showHideImageOfElementId(currentChild.id, displayStatus);
      }
    }
    // Based on cookievalue, change the text in the link to
    // one of the following "Close all submenus" or "Open all submenus"
    toggleDisplayTextAndImage(cookieValue);
  }
}

/**
 * Toggles the display text and display image of
 * 'Close/Open all submenus' link present in the left side nav
 */
function toggleDisplayTextAndImage(displayProperty) {
  var showElement = document.getElementById('show_all_submenus');
  var hideElement = document.getElementById('hide_all_submenus');
  if (showElement && hideElement) {
    // when data objects are shown, display 'Close all submenus' string and
    // when data objects are hidden, display 'Open all submenus' string
    if (displayProperty == 'show') {
      showElement.style.display = 'none';
      hideElement.style.display = 'block';
    } else if (displayProperty == 'hide') {
      showElement.style.display = 'block';
      hideElement.style.display = 'none';
    }
  }
}

/**
 * For the given id, the function returns its 'display' property value
 * from 'adwords_api_service_status' cookie.
 * It returns 'not found' when the given id cannot be found in the cookie
 */
function getDisplayStatusFromCookie(divElementId) {
  var foundServiceId = false;
  var cookieElement = '';
  cookieElement = readCookie(webserviceString + "_api_service_status");

  if (cookieElement) {
    var tempArray = new Array();
    tempArray = cookieElement.split('&');
    for (var i = 0; i < tempArray.length; i++) {
      var serviceString = tempArray[i];
      if (serviceString.indexOf(':') != -1) {
        var serviceIdString = serviceString.substring(0,
                                serviceString.indexOf(':'));
        if (serviceIdString == divElementId) {
          foundServiceId = true;
          var displayStatusString =
              serviceString.substring(serviceString.indexOf(':') + 1);
          return displayStatusString;
        }
      }
    }
  }
  if (!foundServiceId) {
      return 'notfound';
  }
}

/**
 * To toggle the image of the given element
 * which is used to open or close its submenu
 */
function toggleImage(imageElement, displayStatus) {
  if (imageElement) {
    if (displayStatus == 'show') {
      imageElement.src = 'minus.gif';
      imageElement.className = 'expandedicon';
    } else if (displayStatus == 'hide') {
      imageElement.src = 'plus.gif';
      imageElement.className = 'collapsedicon';
    }
  }
}

/**
 * Toggles the display of data objects present under
 * the given service object (currentObj)
 */
function toggleSubMenu(currentObj, event) {
  var event = getEventElement(event);
  // get the element from where the event is fired
  var targetElement = getTargetElement(event);
  stopEventPropagation(event);

  if (currentObj &&
    targetElement.tagName == 'IMG' &&
    targetElement.id.indexOf('_image') != -1 ) {
    var imageElement = document.getElementById(currentObj.id + '_image');
    var displayStatus;
    if (imageElement.className == 'expandedicon') {
      displayStatus = "hide";
    } else if (imageElement.className == 'collapsedicon') {
      displayStatus = "show";
    } else {
      displayStatus = "hide";
    }
    toggleImage(imageElement, displayStatus);
    // toggle the display of the submenu present under
    // the given element
    showHideSubMenuOfElementId(currentObj.id, displayStatus);
    // store the display status of the current element
    // to 'adwords_api_service_status' cookie
    storeIntoCookie(currentObj.id, displayStatus);
  }
}

/**
 * Toggles the submenu of 'Api Reference' link present in the
 * left side nav bar
 */
function toggleApiRefElements(apiRefElement, event) {
  if (apiRefElement) {
    toggleSubMenu(apiRefElement, event);
    var subMenuElement = document.getElementById(apiRefElement.id + '_submenu');
    // toggle the display of Open/Close all submenus
    var linkElement = document.getElementById('toggle_all_submenus');
    if (linkElement && subMenuElement ) {
      linkElement.style.display = subMenuElement.style.display;
    }
  }
}

/**
 * Used to toggle following link
 * "Open all submenus" or "Close all submenus"
 */
function showHideToggleAllSubMenusLink(displayStatus) {
  var linkElement = document.getElementById('toggle_all_submenus');
  if (linkElement) {
    if (displayStatus == 'show') {
      linkElement.style.display = 'block';
    } else if (displayStatus == 'hide') {
      linkElement.style.display = 'none';
    }
  }
}

/**
 * Used to toggle the submenu present under the given element
 */
function showHideSubMenuOfElementId(elementId, displayStatus) {
  var subMenuElement = document.getElementById(elementId + '_submenu');
  if (subMenuElement) {
    if (displayStatus == 'show') {
      subMenuElement.style.display = 'block';
    } else if (displayStatus == 'hide') {
      subMenuElement.style.display = 'none';
    }
  }
}

/**
 * Used to toggle the image associated with given element
 */
function showHideImageOfElementId(elementId, displayStatus) {
  var imageElement = document.getElementById(elementId + '_image');
  if (imageElement) {
    toggleImage(imageElement, displayStatus);
  }
}

/**
 * Returns the event object based on the browser
 */
function getEventElement(event) {
  if (!event) {
    event = window.event;
  }
  return event;
}

/**
 * Returns the source element which fired the given event.
 */
function getTargetElement(event) {
  var targetElement;
  if (event.target) {
    targetElement = event.target;
  } else if (event.srcElement) {
    targetElement = event.srcElement;
  }
  if (targetElement.nodeType == 3) {
    targetElement = targetElement.parentNode;
  }
  return targetElement;
}

/**
 * To stop the bubbling of the event
 */
function stopEventPropagation(event) {
  if (event) {
    event.cancelBubble = true;
    if (event.stopPropagation) {
      event.stopPropagation();
    }
  }
}

/**
 * Returns the stylesheet element of the given
 * LINK/STYLE element from the style sheet collection
 * of the document.
 * This function is useful in safari browser
 */
function getStyleSheetElementForStyle(styleElement) {
  if (styleElement) {
    for (var i=0; i < document.styleSheets.length; i++) {
      if(document.styleSheets[i].ownerNode == styleElement) {
        return document.styleSheets[i];
      }
    }
  }
}

/**
 * Stores the display property of the given id into
 * 'adwords_api_service_status' cookie.
 * If element already exists in the cookie, then its value
 * is overwritten or else a new entry is added in the cookie
 */
function storeIntoCookie(id, displayStatus) {
  var cookieValue = '';
  var foundServiceId = false;
  var cookieElement = '';
  cookieElement = readCookie(webserviceString + "_api_service_status");

  if (cookieElement) {
    var tempArray = new Array();
    tempArray = cookieElement.split('&');
    for (var i = 0; i < tempArray.length; i++) {
      var serviceString = tempArray[i];
      if (serviceString.indexOf(':') != -1) {
        var serviceIdString =
            serviceString.substring(0, serviceString.indexOf(':'));
        if (id == serviceIdString) {
          serviceString = serviceIdString + ':' + displayStatus;
          foundServiceId = true;
        }
        if (cookieValue != '') {
          cookieValue = serviceString + '&' + cookieValue;
        } else {
          cookieValue = serviceString;
        }
      }
    }
    if (!foundServiceId && id && displayStatus) {
      cookieValue = id + ':' + displayStatus + '&' + cookieValue;
    }
    if (cookieValue) {
      createCookie(
          webserviceString + '_api_service_status', 
          cookieValue,
          365);
    }
  } else {
    if (id && displayStatus) {
      cookieValue = id + ":" + displayStatus;
      createCookie(
          webserviceString + '_api_service_status',
          cookieValue,
          365);
    }
  }
}

/**
 * Set the version labels in the left navigation menu for onmouseover
 * to black and change mouse pointer to an arrow to indicate that
 * a tool tip will appear.
 */
function mouseoverLabel(obj) {
  obj.style.cursor = 'default';
  obj.style.color = 'black';
}

/**
 * Change the mouse pointer and color back for onmouseout.
 */
function mouseoutLabel(obj) {
  obj.style.color = '';
}

/**
 * Sets the cursor for 'Show/Hide data objects' link in the left side nav
 * for onmouseover
 */
function mouseoverLink(obj) {
  obj.style.cursor = 'pointer';
}

/**
 * Jump to the anchor on the page given by the #string
 * in the URL for the currently loaded page.
 *
 * Required to workaround the "jump to wrong-line" problem
 * that occurs when jumping to an anchor on a page that has
 * dynamically added or removed lines.
 */
function jumpToCurrentAnchor() {
  var indexOfAnchor = window.location.toString().indexOf("#");
  if (indexOfAnchor != -1) {
    window.location = window.location.toString().substring(indexOfAnchor);
  }
}

/**
 * Modifies page URL to contain current view version & diff version as query
 * parameters, where view version is represented by "v" parameter and
 * diff version is represented by "diff" parameter.
 */
function showUrl() {
  var versionSelect = document.getElementById("version-select");
  if (!versionSelect) {
    return;
  }
  var newSearch = "";
  var selectedVersion =
      versionSelect.options[versionSelect.selectedIndex].value;
  if (selectedVersion == "all") {
    newSearch = "?v=all&diff=0";
  } else if (selectedVersion.indexOf("diff") != -1) {
    var versions = selectedVersion.split('-');
    var viewVersion = versions[1];
    var diffVersion = versions[2];
    newSearch = "?v=" + viewVersion + "&diff=" + diffVersion;
  } else {
    newSearch = "?v=" + selectedVersion + "&diff=0";
  }
  if (newSearch) {
    modifySearch_(newSearch);
  }
}

/**
 * Replaces the search string of page URL by input search string.
 * If input search string is empty, returns current page URL unchanged.
 *
 * @newSearch {String} Search string that replaces the existing search string of
 * page URL, if any.
 * @private
 */

function modifySearch_(newSearch) {
  if (!newSearch) {
    return;
  }

  var hash = location.hash;
  var search = location.search;
  var path = location.pathname;
  var url = location.href;
  var prefix = path ? url.substring(0, path) : url;
  var newUrl = '';

  newUrl = prefix + path + newSearch;
  if (hash.length > 1) {
    newUrl += hash;
  }

  location.href = newUrl;
}
