public function drupalForm($server_options, $op)
    {
        $consumer_tokens = ldap_authorization_tokens($this->consumer);
        $form['intro'] = array('#type' => 'item', '#markup' => t('<h1>LDAP to !consumer_name Configuration</h1>', $consumer_tokens));
        //  $form['status_intro'] = array(
        //     '#type' => 'item',
        //   '#title' => t('Part I.  Basics.', $consumer_tokens),
        //  );
        $form['status'] = array('#type' => 'fieldset', '#title' => t('I.  Basics', $consumer_tokens), '#collapsible' => TRUE, '#collapsed' => FALSE);
        $form['status']['sid'] = array('#type' => 'radios', '#title' => t('LDAP Server used in !consumer_name configuration.', $consumer_tokens), '#required' => 1, '#default_value' => $this->sid, '#options' => $server_options);
        $form['status']['consumer_type'] = array('#type' => 'hidden', '#value' => $this->consumerType, '#required' => 1);
        $form['status']['status'] = array('#type' => 'checkbox', '#title' => t('Enable this configuration', $consumer_tokens), '#default_value' => $this->status);
        $form['status']['only_ldap_authenticated'] = array('#type' => 'checkbox', '#title' => t('Only apply the following LDAP to !consumer_name configuration to users authenticated via LDAP.', $consumer_tokens), '#default_value' => $this->onlyApplyToLdapAuthenticated);
        $form['mapping_intro'] = array('#type' => 'item', '#title' => t('Part II.  How are !consumer_namePlural derived from LDAP data?', $consumer_tokens), '#markup' => t('One or more of the following 3 strategies may be used.', $consumer_tokens));
        /**
         *  II A. derive from DN option
         */
        $form['derive_from_dn'] = array('#type' => 'fieldset', '#title' => t('Strategy II.A. Derive !consumer_namePlural from DN in User\'s LDAP Entry ', $consumer_tokens), '#collapsible' => TRUE, '#collapsed' => !$this->deriveFromDn);
        $form['derive_from_dn']['derive_from_dn_preamble'] = array('#type' => 'item', '#markup' => t('Use this strategy if your users\' LDAP entry DNs look like <code>cn=jdoe,<strong>ou=Group1</strong>,cn=example,cn=com</code>
          and <code>Group1</code> maps to the !consumer_name you want.', $consumer_tokens) . t(' See ') . l('http://drupal.org/node/1498558', 'http://drupal.org/node/1498558') . t(' for additional documentation.'));
        $form['derive_from_dn']['derive_from_dn'] = array('#type' => 'checkbox', '#title' => t('!consumer_namePlural are derived from user\'s LDAP entry DN', $consumer_tokens), '#default_value' => $this->deriveFromDn);
        $form['derive_from_dn']['derive_from_dn_attr'] = array('#type' => 'textfield', '#title' => t('Attribute of the User\'s LDAP Entry DN which contains the !consumer_shortName name:', $consumer_tokens), '#default_value' => $this->deriveFromDnAttr, '#size' => 50, '#maxlength' => 255, '#description' => t('In the example above, it would be <code>ou</code>', $consumer_tokens), '#states' => array('visible' => array(':input[name="derive_from_dn"]' => array('checked' => TRUE))));
        /**
         *  II B. derive from attributes option
         */
        $form['derive_from_attr'] = array('#type' => 'fieldset', '#title' => t('Strategy II.B. Derive !consumer_namePlural from Attribute in User\'s LDAP Entry', $consumer_tokens), '#collapsible' => TRUE, '#collapsed' => !$this->deriveFromAttr);
        $form['derive_from_attr']['derive_from_entry_preamble'] = array('#type' => 'item', '#markup' => '<p>' . t('Use this strategy if users\' LDAP entries contains an attribute such as <code>memberOf</code> that contains a list of groups
          the user belongs to.  Typically only one attribute name would be used.  See ') . l('http://drupal.org/node/1487018', 'http://drupal.org/node/1487018') . t(' for additional documentation.') . '</p>');
        $form['derive_from_attr']['derive_from_attr'] = array('#type' => 'checkbox', '#title' => t('!consumer_namePlural are specified by LDAP attributes', $consumer_tokens), '#default_value' => $this->deriveFromAttr);
        $form['derive_from_attr']['derive_from_attr_attr'] = array('#type' => 'textarea', '#title' => t('Attribute name(s) (one per line)'), '#default_value' => $this->arrayToLines($this->deriveFromAttrAttr), '#cols' => 50, '#rows' => 1, '#description' => NULL, '#states' => array('visible' => array(':input[name="derive_from_attr"]' => array('checked' => TRUE))));
        $form['derive_from_attr']['derive_from_attr_use_first_attr'] = array('#type' => 'checkbox', '#title' => t('Convert full dn to value of first attribute.  e.g.  <code>cn=admin group,ou=it,dc=ad,dc=nebraska,dc=edu</code> would be converted to <code>admin group</code>', $consumer_tokens), '#default_value' => $this->deriveFromAttrUseFirstAttr, '#states' => array('visible' => array(':input[name="derive_from_attr"]' => array('checked' => TRUE))));
        $nested_warning = t('Warning: this is fairly new and untested feature.  Please test a few users with the !consumer_testLink form first.
      Nested groups also involves more queries which require the service account or other binding account to be able to query the nested groups.
      If using nested groups, consider less, higher level base dns in the server configuration for more efficient queries.', $consumer_tokens);
        $form['derive_from_attr']['derive_from_attr_nested'] = array('#type' => 'checkbox', '#title' => t('Include nested groups. ', $consumer_tokens) . $nested_warning, '#default_value' => $this->deriveFromAttrNested, '#states' => array('visible' => array(':input[name="derive_from_attr"]' => array('checked' => TRUE))));
        /**
         *  II C. derive from entry option
         */
        $form['derive_from_entry'] = array('#type' => 'fieldset', '#title' => t('Strategy II.C. Derive !consumer_namePlural from LDAP Group entries', $consumer_tokens), '#collapsible' => TRUE, '#collapsed' => !$this->deriveFromEntry);
        $form['derive_from_entry']['derive_from_entry_preamble'] = array('#type' => 'item', '#markup' => t('Use this strategy if your LDAP has entries for groups and strategy II.B. is not applicable.') . t(' See ') . l('http://drupal.org/node/1499172', 'http://drupal.org/node/1499172') . t(' for additional documentation.'));
        $form['derive_from_entry']['derive_from_entry'] = array('#type' => 'checkbox', '#title' => t('!consumer_namePlural exist as LDAP entries where a multivalued attribute contains the members', $consumer_tokens), '#default_value' => $this->deriveFromEntry);
        $form['derive_from_entry']['derive_from_entry_entries'] = array('#type' => 'textarea', '#title' => t('LDAP DNs containing !consumer_shortNamePlural (one per line)', $consumer_tokens), '#default_value' => $this->arrayToLines($this->deriveFromEntryEntries), '#cols' => 50, '#rows' => 6, '#description' => t('Enter a list of LDAP entries where !consumer_namePlural should be searched for.', $consumer_tokens), '#states' => array('visible' => array(':input[name="derive_from_entry"]' => array('checked' => TRUE))));
        $form['derive_from_entry']['derive_from_entry_entries_attr'] = array('#type' => 'textfield', '#title' => t('Attribute holding the previous list of values. e.g. cn, dn', $consumer_tokens), '#default_value' => $this->deriveFromEntryEntriesAttr, '#size' => 50, '#maxlength' => 255, '#description' => t('If the above lists are ldap cns, this should be "cn", if they are ldap dns, this should be "dn"', $consumer_tokens), '#states' => array('visible' => array(':input[name="derive_from_entry"]' => array('checked' => TRUE))));
        $form['derive_from_entry']['derive_from_entry_attr'] = array('#type' => 'textfield', '#title' => t('Attribute holding !consumer_namePlural members', $consumer_tokens), '#default_value' => $this->deriveFromEntryMembershipAttr, '#size' => 50, '#maxlength' => 255, '#description' => t('Name of the multivalued attribute which holds the !consumer_namePlural members,
         for example: uniquemember, memberUid', $consumer_tokens), '#states' => array('visible' => array(':input[name="derive_from_entry"]' => array('checked' => TRUE))));
        // deriveFromEntryAttrMatchingUserAttr
        $form['derive_from_entry']['derive_from_entry_user_ldap_attr'] = array('#type' => 'textfield', '#title' => t('User LDAP Entry attribute held in "', $consumer_tokens) . $form['derive_from_entry']['derive_from_entry_attr']['#title'] . '"', '#default_value' => $this->deriveFromEntryAttrMatchingUserAttr, '#size' => 50, '#maxlength' => 255, '#description' => t('This is almost always "dn" or "cn".') . '<br/>' . t('For example if the attribute holding members is "uniquemember" and that the group entry has the following uniquemember values: ') . '<code>
      uniquemember[0]=uid=joeprogrammer,ou=it,dc=ad,dc=myuniversity,dc=edu<br/>
      uniquemember[1]=cn=sysadmins,cn=groups,dc=ad,dc=myuniversity,dc=edu
      </code><br/>' . t('"dn" would be used because uid=joeprogrammer,ou=it,dc=ad,dc=myuniversity,dc=edu and cn=sysadmins,cn=groups,dc=ad,dc=myuniversity,dc=edu are the dn\'s of the LDAP entries.') . '<br/>' . t('If the attribute holding members is member and that the group entry has: ') . '<br/><code>
      member[0]=joeprogrammer<br/>
      member[1]=sysadmins
      </code><br/>' . t('"cn" would be used because joeprogrammer and sysadmins are the cn\'s of the LDAP entries.'), '#states' => array('visible' => array(':input[name="derive_from_entry"]' => array('checked' => TRUE))));
        $form['derive_from_entry']['derive_from_entry_use_first_attr'] = array('#type' => 'checkbox', '#title' => t('Convert full dn to value of first attribute.  e.g.  <code>cn=admin group,ou=it,dc=ad,dc=nebraska,dc=edu</code> would be converted to <code>admin group</code>', $consumer_tokens), '#default_value' => $this->deriveFromEntryUseFirstAttr, '#states' => array('visible' => array(':input[name="derive_from_entry"]' => array('checked' => TRUE))));
        $form['derive_from_entry']['derive_from_entry_search_all'] = array('#type' => 'checkbox', '#title' => t('Search all enabled LDAP servers for matching users.  This Enables roles on one server referencing users on another.
        This can lead to [Number of Enabled Servers] x [Number of Base DNs] x [Number of Groups] queries;
        so don\'t enable this unless you know its useful to your use case.'), '#default_value' => $this->deriveFromEntrySearchAll, '#states' => array('visible' => array(':input[name="derive_from_entry"]' => array('checked' => TRUE))));
        $form['derive_from_entry']['derive_from_entry_nested'] = array('#type' => 'checkbox', '#title' => t('Include nested groups.', $consumer_tokens) . $nested_warning, '#default_value' => $this->deriveFromEntryNested, '#states' => array('visible' => array(':input[name="derive_from_entry"]' => array('checked' => TRUE))));
        /**
         *  filter and whitelist
         */
        // $form['filter_intro'] = array(
        //   '#type' => 'item',
        //   '#title' => t('Part III.  Mapping and White List.', $consumer_tokens),
        //  '#markup' => t('The rules in Part I. and II. will create a list of "raw authorization ids".
        //    Part III. determines how these are mapped to!consumer_namePlural.', $consumer_tokens),
        //  );
        if (method_exists($this->consumer, 'mappingExamples')) {
            $consumer_tokens['!examples'] = '<fieldset class="collapsible collapsed form-wrapper" id="authorization-mappings">
<legend><span class="fieldset-legend">' . t('Examples base on current !consumer_namePlural', $consumer_tokens) . '</span></legend>
<div class="fieldset-wrapper">' . $this->consumer->mappingExamples($consumer_tokens) . '<div class="fieldset-wrapper">
</fieldset>';
        } else {
            $consumer_tokens['!examples'] = '';
        }
        $form['filter_and_mappings'] = array('#type' => 'fieldset', '#title' => t('III. LDAP to !consumer_name mapping and filtering', $consumer_tokens), '#description' => t('
The settings in part II generate a list of "raw authorization ids" which
need to be converted to !consumer_namePlural.
Raw authorization ids look like:
<ul>
<li><code>Campus Accounts</code> (...from II.A)</li>
<li><code>ou=Underlings,dc=myorg,dc=mytld,dc=edu</code> (...from II.B and II.C.)</li>
<li><code>ou=IT,dc=myorg,dc=mytld,dc=edu</code> (...from II.B and II.C.)</li>
</ul>

<p><strong>Mappings are often needed to convert these "raw authorization ids" to !consumer_namePlural.</strong></p>

!consumer_mappingDirections

!examples

', $consumer_tokens), '#collapsible' => TRUE, '#collapsed' => !($this->mappings || $this->useMappingsAsFilter));
        $form['filter_and_mappings']['mappings'] = array('#type' => 'textarea', '#title' => t('Mapping of LDAP to !consumer_name (one per line)', $consumer_tokens), '#default_value' => $this->arrayToPipeList($this->mappings), '#cols' => 50, '#rows' => 5);
        $form['filter_and_mappings']['use_filter'] = array('#type' => 'checkbox', '#title' => t('Use LDAP group to !consumer_namePlural filtering', $consumer_tokens), '#default_value' => $this->useMappingsAsFilter, '#description' => t('If enabled, only above mapped !consumer_namePlural will be assigned.
        <strong>If not checked, many !consumer_namePlural may be created.</strong>', $consumer_tokens));
        $form['advanced_intro'] = array('#type' => 'item', '#title' => t('Part IV.  Even More Settings.', $consumer_tokens), '#markup' => t('', $consumer_tokens));
        /**
        *
        * @todo for 7.x-2.x
         $form['advanced_intro'] = array(
               '#type' => 'item',
               '#title' => t('IV.A. Map in both directions.', $consumer_tokens),
               '#markup' => t('', $consumer_tokens),
           );
        
        
          $form['misc_settings']['allow_synch_both_directions'] = array(
             '#type' => 'checkbox',
             '#disabled' => !$this->consumer->allowSynchBothDirections,
             '#default_value' => $this->synchToLdap,
             '#title' => t('Check this option if you want LDAP data to be modified if a user
               has a !consumer_name.  In other words, synchronize both ways.  For this to work the ldap server
               needs to writeable, the right side of the mappings list must be unique, and I.B or I.C.
               derivation must be used.', $consumer_tokens),
           );
        */
        $synchronization_modes = array();
        if ($this->synchOnLogon) {
            $synchronization_modes[] = 'user_logon';
        }
        $form['misc_settings']['synchronization_modes'] = array('#type' => 'checkboxes', '#title' => t('IV.B. When should !consumer_namePlural be granted/revoked from user?', $consumer_tokens), '#options' => array('user_logon' => t('When a user logs on'), 'manually' => t('Manually or via another module')), '#default_value' => $synchronization_modes, '#description' => t('<p>"When a user logs on" is the common way to do this.</p>', $consumer_tokens));
        $synchronization_actions = array();
        if ($this->revokeLdapProvisioned) {
            $synchronization_actions[] = 'revoke_ldap_provisioned';
        }
        if ($this->createConsumers) {
            $synchronization_actions[] = 'create_consumers';
        }
        if ($this->regrantLdapProvisioned) {
            $synchronization_actions[] = 'regrant_ldap_provisioned';
        }
        $options = array('revoke_ldap_provisioned' => t('Revoke !consumer_namePlural previously granted by LDAP Authorization but no longer valid.', $consumer_tokens), 'regrant_ldap_provisioned' => t('Re grant !consumer_namePlural previously granted by LDAP Authorization but removed manually.', $consumer_tokens));
        if ($this->consumer->allowConsumerObjectCreation) {
            $options['create_consumers'] = t('Create !consumer_namePlural if they do not exist.', $consumer_tokens);
        }
        $form['misc_settings']['synchronization_actions'] = array('#type' => 'checkboxes', '#title' => t('IV.C. What actions would you like performed when !consumer_namePlural are granted/revoked from user?', $consumer_tokens), '#options' => $options, '#default_value' => $synchronization_actions);
        /**
         * @todo  some general options for an individual mapping (perhaps in an advance tab).
         *
         * - on synchronization allow: revoking authorizations made by this module, authorizations made outside of this module
         * - on synchronization create authorization contexts not in existance when needed (drupal roles etc)
         * - synchronize actual authorizations (not cached) when granting authorizations
         */
        switch ($op) {
            case 'add':
                $action = 'Add';
                break;
            case 'edit':
                $action = 'Save';
                break;
            case 'delete':
                $action = 'Delete';
                break;
        }
        $form['submit'] = array('#type' => 'submit', '#value' => $action);
        return $form;
    }
    public function drupalForm($server_options, $op)
    {
        $consumer_tokens = ldap_authorization_tokens($this->consumer);
        $form['intro'] = array('#type' => 'item', '#markup' => t('<h1>LDAP to !consumer_name Configuration</h1>', $consumer_tokens));
        $form['status'] = array('#type' => 'fieldset', '#title' => t('I.  Basics', $consumer_tokens), '#collapsible' => TRUE, '#collapsed' => FALSE);
        $form['status']['sid'] = array('#type' => 'radios', '#title' => t('LDAP Server used in !consumer_name configuration.', $consumer_tokens), '#required' => 1, '#default_value' => $this->sid, '#options' => $server_options);
        $form['status']['consumer_type'] = array('#type' => 'hidden', '#value' => $this->consumerType, '#required' => 1);
        $form['status']['status'] = array('#type' => 'checkbox', '#title' => t('Enable this configuration', $consumer_tokens), '#default_value' => $this->status);
        $form['status']['only_ldap_authenticated'] = array('#type' => 'checkbox', '#title' => t('Only apply the following LDAP to !consumer_name configuration to users authenticated via LDAP.  On uncommon reason for disabling this is when you are using Drupal authentication, but want to leverage LDAP for authorization; for this to work the Drupal username still has to map to an LDAP entry.', $consumer_tokens), '#default_value' => $this->onlyApplyToLdapAuthenticated);
        if (method_exists($this->consumer, 'mappingExamples')) {
            $consumer_tokens['!examples'] = '<fieldset class="collapsible collapsed form-wrapper" id="authorization-mappings">
<legend><span class="fieldset-legend">' . t('Examples based on current !consumer_namePlural', $consumer_tokens) . '</span></legend>
<div class="fieldset-wrapper">' . $this->consumer->mappingExamples($consumer_tokens) . '<div class="fieldset-wrapper">
</fieldset>';
        } else {
            $consumer_tokens['!examples'] = '';
        }
        $form['filter_and_mappings'] = array('#type' => 'fieldset', '#title' => t('II. LDAP to !consumer_name mapping and filtering', $consumer_tokens), '#description' => t('
Representations of groups derived from LDAP might initially look like:
<ul>
<li><code>cn=students,ou=groups,dc=hogwarts,dc=edu</code></li>
<li><code>cn=gryffindor,ou=groups,dc=hogwarts,dc=edu</code></li>
<li><code>cn=faculty,ou=groups,dc=hogwarts,dc=edu</code></li>
<li><code>cn=probation students,ou=groups,dc=hogwarts,dc=edu</code></li>
</ul>

<p><strong>Mappings are used to convert and filter these group representations to !consumer_namePlural.</strong></p>

!consumer_mappingDirections

!examples

', $consumer_tokens), '#collapsible' => TRUE, '#collapsed' => !($this->mappings || $this->useMappingsAsFilter || $this->useFirstAttrAsGroupId));
        $form['filter_and_mappings']['use_first_attr_as_groupid'] = array('#type' => 'checkbox', '#title' => t('Convert full dn to value of first attribute before mapping.  e.g.  <code>cn=students,ou=groups,dc=hogwarts,dc=edu</code> would be converted to <code>students</code>', $consumer_tokens), '#default_value' => $this->useFirstAttrAsGroupId);
        $form['filter_and_mappings']['mappings'] = array('#type' => 'textarea', '#title' => t('Mapping of LDAP to !consumer_name (one per line)', $consumer_tokens), '#default_value' => $this->mappingsToPipeList($this->mappings), '#cols' => 50, '#rows' => 5);
        $form['filter_and_mappings']['use_filter'] = array('#type' => 'checkbox', '#title' => t('Only grant !consumer_namePlural that match a filter above.', $consumer_tokens), '#default_value' => $this->useMappingsAsFilter, '#description' => t('If enabled, only above mapped !consumer_namePlural will be assigned (e.g. students and administrator).
        <strong>If not checked, !consumer_namePlural not mapped above also may be created and granted (e.g. gryffindor and probation students).  In some LDAPs this can lead to hundreds of !consumer_namePlural being created if "Create !consumer_namePlural if they do not exist" is enabled below.
        </strong>', $consumer_tokens));
        $form['more'] = array('#type' => 'fieldset', '#title' => t('Part III.  Even More Settings.'), '#collapsible' => TRUE, '#collapsed' => FALSE);
        $synchronization_modes = array();
        if ($this->synchOnLogon) {
            $synchronization_modes[] = 'user_logon';
        }
        $form['more']['synchronization_modes'] = array('#type' => 'checkboxes', '#title' => t('When should !consumer_namePlural be granted/revoked from user?', $consumer_tokens), '#options' => array('user_logon' => t('When a user logs on.')), '#default_value' => $synchronization_modes, '#description' => '');
        $synchronization_actions = array();
        if ($this->revokeLdapProvisioned) {
            $synchronization_actions[] = 'revoke_ldap_provisioned';
        }
        if ($this->createConsumers) {
            $synchronization_actions[] = 'create_consumers';
        }
        if ($this->regrantLdapProvisioned) {
            $synchronization_actions[] = 'regrant_ldap_provisioned';
        }
        $options = array('revoke_ldap_provisioned' => t('Revoke !consumer_namePlural previously granted by LDAP Authorization but no longer valid.', $consumer_tokens), 'regrant_ldap_provisioned' => t('Re grant !consumer_namePlural previously granted by LDAP Authorization but removed manually.', $consumer_tokens));
        if ($this->consumer->allowConsumerObjectCreation) {
            $options['create_consumers'] = t('Create !consumer_namePlural if they do not exist.', $consumer_tokens);
        }
        $form['more']['synchronization_actions'] = array('#type' => 'checkboxes', '#title' => t('What actions would you like performed when !consumer_namePlural are granted/revoked from user?', $consumer_tokens), '#options' => $options, '#default_value' => $synchronization_actions);
        /**
         * @todo  some general options for an individual mapping (perhaps in an advance tab).
         *
         * - on synchronization allow: revoking authorizations made by this module, authorizations made outside of this module
         * - on synchronization create authorization contexts not in existance when needed (drupal roles etc)
         * - synchronize actual authorizations (not cached) when granting authorizations
         */
        switch ($op) {
            case 'add':
                $action = 'Add';
                break;
            case 'edit':
                $action = 'Save';
                break;
            case 'delete':
                $action = 'Delete';
                break;
        }
        $form['submit'] = array('#type' => 'submit', '#value' => $action);
        return $form;
    }