/// <summary>
        /// Build a LDAP Query String. Dependant on SearchBuilder.
        /// </summary>
        /// <param name="Attrib"></param>
        /// <param name="Data"></param>
        /// <returns></returns>
        string SearchStringBuilder(CaseLDAPSearchAttributes Attrib, string Data)
        {
            string retVal = null;
            switch (Attrib)
            {
                case CaseLDAPSearchAttributes.WholeName:
                    retVal = "(cn=" + Data + ")";
                    break;
                case CaseLDAPSearchAttributes.LastName:
                    retVal = "(sn=" + Data + ")";
                    break;
                case CaseLDAPSearchAttributes.Telephone:

                    if (Data.Length == 4)
                        Data = "216368" + Data;
                    else if (Data.Length == 7)
                        Data = "216" + Data;

                    retVal = "(telephonenumber=" + Data + ")";
                    break;
                case CaseLDAPSearchAttributes.UserID:
                    retVal = "(uid=" + Data + ")";
                    break;
                case CaseLDAPSearchAttributes.Language:
                    retVal = "(preferredLanguage=" + Data + ")";
                    break;
                case CaseLDAPSearchAttributes.DeptNumber:
                    retVal = "(departmentNumber=" + Data + ")";
                    break;
                case CaseLDAPSearchAttributes.Raw:
                    retVal = Data;
                    break;
                default:
                    throw new Exception("Invalid type of search");
            }
            return retVal;
        }
        public CaseLDAPReturn Search(CaseLDAPSearchAttributes searchMethod, string Term, bool getDetails = false)
        {
            TimeSpan ADSTime = new TimeSpan(0);
            if(searchMethod == CaseLDAPSearchAttributes.ADSGroup) //if we are searching ADS user groups.. 
            {
                searchMethod = CaseLDAPSearchAttributes.UserID;  //We are expecting a list of case ids. 
                Stopwatch searchADSTime = new Stopwatch(); //Time our search
                searchADSTime.Start();                
                Term = string.Join(",", ads.UsersInGroup(Term)); //combine our users into a comma seperated string. Our serach builders already handle this
                searchADSTime.Stop();
                ADSTime = searchADSTime.Elapsed;
            }



            DirectoryEntry entry = new DirectoryEntry(Options.LDAPServer, null, null, AuthenticationTypes.Anonymous); //Connect to LDAP
            //entry.Username = "******";
            //entry.Password = "******";                
            DirectorySearcher mySearcher = new DirectorySearcher { SearchRoot = entry, SearchScope = SearchScope.Subtree, Filter = SearchBuilder(searchMethod, Term) };


            Stopwatch searchTime = new Stopwatch(); //Time our search
            searchTime.Start();
            SearchResultCollection results = mySearcher.FindAll(); //Query LDAP
            _retval.ResultsCount = results.Count; 
                       
           
            if (results.Count > 0)
            {
                StringBuilder resultsOutput = new StringBuilder();



                foreach (SearchResult result in results)
                {
                    CaseLDAPSearchResults sr = new CaseLDAPSearchResults(); //Our Results object is meant to be serializable from ldap. We had to create a seperate object to handle this. Later we us reflection to publish to this object.

                    /* Another way.
                    DirectoryEntry e = result.GetDirectoryEntry(); 
                    foreach(PropertyValueCollection property in entry.Properties)
                    {
                        foreach(var val in property)
                        {
                            string key = property.PropertyName
                            string value = val.ToString()                            
                            ...
                        }
                    }
                    */
                    if (!getDetails) //if a less detailed search is requested
                    {
                        sr.cn = (result.Properties["cn"].Count > 0) ? result.Properties["cn"][0].ToString() : null;
                        sr.uid = (result.Properties["uid"].Count > 0) ? result.Properties["uid"][0].ToString() : null;
                        sr.telephonenumber = (result.Properties["telephonenumber"].Count > 0) ? result.Properties["telephonenumber"][0].ToString() : null;
                        sr.mail = (result.Properties["mail"].Count > 0) ? result.Properties["mail"][0].ToString() : null;
                        sr.physicaldeliveryofficename = (result.Properties["physicaldeliveryofficename"].Count > 0) ? result.Properties["physicaldeliveryofficename"][0].ToString() : null;
                        sr.title = (result.Properties["title"].Count > 0) ? result.Properties["title"][0].ToString() : null;
                        sr.ou = (result.Properties["ou"].Count > 0) ? result.Properties["ou"][0].ToString() : null;
                        foreach (var m in result.Properties["mailequivalentaddress"])
                        {
                            sr.mailequivalentaddress.Add(m.ToString());
                        }
                    }
                    else
                    {
                        foreach (string key in result.Properties.PropertyNames) //Loop through our keys and properties. The way it's setup is kind of odd. so we have nested loops.
                        {
                            foreach (object val in result.Properties[key])
                            {

                                //resultsOutput.Append(String.Format("{0}: {1}, ", key, property.ToString()));
                                //_retval.SearchResults.Add(new KeyValuePair<string, string>(key, property.ToString()));

                                //UGH. Using reflection to store our values into a serializable object.

                                var prop = sr.GetType().GetProperty(key); //Get the property of our results object that matches the key. 
                                if (prop != null) //if there is a different key than what is in LDAP then put it in an array of other stuff. 
                                {
                                    if (prop.PropertyType == typeof(string)) //There are two types of properties in our results object. string and list of string.
                                    {
                                        prop.SetValue(sr, val.ToString());
                                    }
                                    else if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(List<>))
                                    {
                                        switch (prop.Name) //if there is many values for an ldap object put in in an array and we'll serialize that to JSON. 
                                        {
                                            case "mailequivalentaddress":
                                                sr.mailequivalentaddress.Add(val.ToString());
                                                break;
                                            case "objectclass":
                                                sr.objectclass.Add(val.ToString());
                                                break;
                                            default:
                                                sr.otherstuff.Add(new KeyValuePair<string, string>(key, val.ToString()));
                                                break;
                                        }
                                    }
                                }
                                else
                                {
                                    sr.otherstuff.Add(new KeyValuePair<string, string>(key, val.ToString()));
                                }
                            }
                        }
                    }
                    _retval.SearchResults.Add(sr); //add our results to be serialized.
                }           
            }
            searchTime.Stop();
            TimeSpan ts = searchTime.Elapsed;
            ts = ts.Add(ADSTime); //if there was an ADS Search add that to our search time.. 

            _retval.SearchTime = String.Format("{0:00}.{1:0000}", ts.Seconds, ts.Milliseconds);
            return _retval;
        }
        /// <summary>
        /// Entry Point to build our query for LDAP, We don't allow complex queries when the attribute is not raw. if they need more they can make thier own damn query. 
        /// </summary>
        /// <param name="Attrib">Our Attributes</param>
        /// <param name="Data">our data to convert to LDAP srting</param>
        /// <returns></returns>
        private string SearchBuilder(CaseLDAPSearchAttributes Attrib, string Data)
        {
            StringBuilder BatchRetVal = new StringBuilder();

            string[] batch = Data.Split(new string[] { "\n", "," }, StringSplitOptions.RemoveEmptyEntries); //We are expecting 
            if (batch.Length > 1) //allowing for single searches in a batch box. 
                BatchRetVal.Append("(|"); //if there is more than one the query (|(query=data)(query2=data2)...(queryN=dataN)) works. So we need to appead the OR operation
            foreach (string data in batch)
                BatchRetVal.Append(SearchStringBuilder(Attrib, data));
            if (batch.Length > 1) //allowing for single searches in a batch box. Close our expresion.
                BatchRetVal.Append(")");
            return BatchRetVal.ToString();
        }