﻿
// ----------------------------------------------------------------------------------
//  The link between searchcontroller and individual controls. Keeps record of 
//  event subscriptions and triggers.
// ----------------------------------------------------------------------------------
function FlowController()
{
    this.EventSubscriptions = new Array();
    this.Triggers = new Array();
    this.searchControllers = new Array();
    this.searchResultNum=0; // how many times have we received a result from a searchcontroller?
    var self = this;

    // ------------------------------------------------------------------------------
    //  Subscribe to Flowcontroller for events from Searchcontroller.
    // ------------------------------------------------------------------------------
    this.SubscribeEvent = function(subscriberObj, searchController, eventName, callbackMethod)
    {
        //debug('Flowcontroller.SubscriveEvent(sc='+searchController.name+", eventName="+eventName+')');
        DebugAddTab();
        
        var r = new EventSubscription();
        r.subscriberObj = subscriberObj;
        r.eventName = eventName;
        r.method = callbackMethod;
        r.Originator = searchController;
        this.EventSubscriptions.push(r);   
        
        DebugRemoveTab();         
    }
    
    this.TriggerBeginSearchEvent = function(searchcontroller)
    {
       for(var i=0; i<fc.EventSubscriptions.length; i++)
       {
            if ( (fc.EventSubscriptions[i].Originator.name == searchcontroller.name) && (fc.EventSubscriptions[i].eventName == "BeginSearch" ) )
            {
                fc.EventSubscriptions[i].method();
            }
       }    
    }
    
    // ------------------------------------------------------------------------------
    //  Register the relationship between someone who triggers an event (a control) 
    //  and searchController. This way flowcontroller will know to notify
    //  only those who subscribe to certain search controllers.
    //  A control can trigger events to more than one searchcontroller. 
    // ------------------------------------------------------------------------------
    this.RegisterTrigger = function(name, searchController)
    {
        debug('Flowcontroller.RegisterTrigger(sc='+searchController.name+", name="+name+')');
        var t = new Trigger();
        t.name = name;
        t.targetObj = searchController;
        this.Triggers.push(t);
        
        for (var i=0; i<self.searchControllers.length; i++)
        {
            if (self.searchControllers[i].name == searchController.name)
                return;      
        }
        self.searchControllers.push(searchController);
    }

    // ------------------------------------------------------------------------------
    //  Clear all criteria for all searchcontrollers which you (name) are reistered as
    //  trigger for. No search is initiated.
    // ------------------------------------------------------------------------------    
    this.ClearAllCriteria = function(name)
    {
        for (i=0; i<fc.Triggers.length; i++)
        {   
            if (fc.Triggers[i].name == name)
            {                
                fc.Triggers[i].targetObj.ClearAllCriteria();                             
            }
        }         
    }
        
    // ------------------------------------------------------------------------------
    // A ControlMultiCheckbox has changed criteria. Do a search on each 
    // searchcontroller the control has a relationship with (determined via method
    // RegisterTrigger() ).
    // ------------------------------------------------------------------------------
    this.CriteriaChange_ControlMultiCheckbox = function(name, controlMultiCheckboxCriteria, triggerSearch)
    {     
        debug("CriteriaChange_ControlMultiCheckbox("+name+")"+fc.Triggers.length+ " "+controlMultiCheckboxCriteria.length);        
        for (i=0; i<fc.Triggers.length; i++)
        {   
            if (fc.Triggers[i].name == name)
            {                
                fc.Triggers[i].targetObj.SetMultiCheckboxCriteria(name, controlMultiCheckboxCriteria);
                
                if (triggerSearch)
                {
                    this.TriggerBeginSearchEvent(fc.Triggers[i].targetObj);
                    fc.Triggers[i].targetObj.DoSearch(this.OnSearchResult); 
                }              
            }
        }             
    }
 
    // ------------------------------------------------------------------------------
    // A ControlMultiLevelCheckbox has changed criteria. Do a search on each 
    // searchcontroller the control has a relationship with (determined via method
    // RegisterTrigger() ).
    // Parameter 'name' is the name of the control or entity which is registered as 
    // trigger.
    // ------------------------------------------------------------------------------   
    this.CriteriaChange_ControlMultiLevelCheckbox = function(name, multiCheckboxCriteria, triggerSearch)
    {
        debug("CriteriaChange_ControlMultiLevelCheckbox triggerSearch="+triggerSearch)
        debug("CriteriaChange_ControlMultiLevelCheckbox("+name+")" );   
        DebugAddTab();       
        var num=0;
        for (i=0; i<fc.Triggers.length; i++)
        {   
            if (fc.Triggers[i].name == name)
            {       
                num++;          
                fc.Triggers[i].targetObj.SetMultiLevelCheckboxCriteria(name, multiCheckboxCriteria);
                if (triggerSearch)
                {
                    this.TriggerBeginSearchEvent(fc.Triggers[i].targetObj);
                    fc.Triggers[i].targetObj.DoSearch(this.OnSearchResult);   
                }                    
            }
        }         
        if (num==0)
        {
            debug("No trigger under the name '"+name+"' was registered!");
        }
        DebugRemoveTab();
        debug("~CriteriaChange_ControlMultiLevelCheckbox("+name+")");          
    }
    
    // ------------------------------------------------------------------------------
    // Parameter 'name' is the name of the control or entity which is registered as 
    // trigger.
    // ------------------------------------------------------------------------------   
    this.CriteriaChange_Freetext = function(name, text)
    {
        for (i=0; i<fc.Triggers.length; i++)
        {   
            debug("trigger:"+fc.Triggers[i].name+" == "+name+" ?");
            if (fc.Triggers[i].name == name)
            {
                fc.Triggers[i].targetObj.SetFreetextCriteria(text); 
                this.TriggerBeginSearchEvent(fc.Triggers[i].targetObj);
                fc.Triggers[i].targetObj.DoSearch(this.OnSearchResult); 
            }
        }        
    }
 
    // ------------------------------------------------------------------------------
    // The price range to include in search.
    // Parameter 'name' is the name of the control or entity which is registered as 
    // trigger.
    // ------------------------------------------------------------------------------     
    this.CriteriaChange_MinMaxPrice = function(name, min, max,  triggerSearch)
    {
        for (i=0; i<fc.Triggers.length; i++)
        {   
            //debug("trigger:"+fc.Triggers[i].name+" == "+name+" ?");
            if (fc.Triggers[i].name == name)
            {
                fc.Triggers[i].targetObj.SetMinMaxPrice(min, max);
                if (triggerSearch)
                {
                    this.TriggerBeginSearchEvent(fc.Triggers[i].targetObj);
                    fc.Triggers[i].targetObj.DoSearch(this.OnSearchResult); 
                }
            }
        }     
    }
	
	this.CriteriaChange_MinMaxPriceRange = function(name, minrange, maxrange, triggerSearch)
	{
        for (i=0; i<fc.Triggers.length; i++)
        {   
            if (fc.Triggers[i].name == name)
            {
                fc.Triggers[i].targetObj.MinMaxPriceRange(minrange, maxrange);
                if (triggerSearch)
                {
                    //fc.Triggers[i].targetObj.DoSearch(this.OnSearchResult); 
                }
            }
        }     
    }

    // ------------------------------------------------------------------------------
    // Parameter 'name' is the name of the control or entity which is registered as 
    // trigger.
    // ------------------------------------------------------------------------------     
    this.CriteriaChange_Pagesize = function(name, size)
    {
        for (i=0; i<fc.Triggers.length; i++)
        {   
            //debug("trigger:"+fc.Triggers[i].name+" == "+name+" ?");
            if (fc.Triggers[i].name == name)
            {
                fc.Triggers[i].targetObj.SetPageSize(size); 
                this.TriggerBeginSearchEvent(fc.Triggers[i].targetObj);
                fc.Triggers[i].targetObj.DoSearch(this.OnSearchResult); 
            }
        }        
    }
   
    // ------------------------------------------------------------------------------
    // Trigger search for a searchcontroller. Call ClearAllCriteria() first if you 
    // wish to do ALL search (unless no criteria has been set so far). 
    // ------------------------------------------------------------------------------  
    this.TriggerSearch = function(searchController)
    {
        this.TriggerBeginSearchEvent(searchController);
        searchController.DoSearch(this.OnSearchResult);  
    }
  
    // ------------------------------------------------------------------------------
    // Parameter 'name' is the name of the control or entity which is registered as 
    // trigger.
    // Parameters:
    //      name:       The name of the control or entity which is registered as trigger.
    //      sortField:  The field (one of the fields in a result document) to sort by. 
    //      dir:        "asc" or "desc".
    // ------------------------------------------------------------------------------       
    this.CriteriaChange_Sorting = function(name, sortField, dir)
    {
        debug("CriteriaChange_Sorting(name="+name+", sortField="+sortField+", dir="+dir);
        for (i=0; i<fc.Triggers.length; i++)
        {   
            //debug("trigger:"+fc.Triggers[i].name+" == "+name+" ?");
            if (fc.Triggers[i].name == name)
            {
                //debug("Sort Criteria change '"+name+"'"); 
                fc.Triggers[i].targetObj.SetSortCriteria(sortField, dir);
                this.TriggerBeginSearchEvent(fc.Triggers[i].targetObj);
                fc.Triggers[i].targetObj.DoSearch(this.OnSearchResult); 
            } 
        }
    }
 
    // ------------------------------------------------------------------------------
    // Parameter 'name' is the name of the control or entity which is registered as 
    // trigger.
    // Parameters:
    //      name:       The name of the control or entity which is registered as trigger.
    //      page:       The page of a result to show. Starts from zero.  
    // ------------------------------------------------------------------------------     
    this.CriteriaChange_Page = function(name, page)
    {
        for (i=0; i<fc.Triggers.length; i++)
        {   
            //debug("trigger:"+fc.Triggers[i].name+" == "+name+" ?");
            if (fc.Triggers[i].name == name)
            {
                //debug("Criteria page change '"+name+"'");
                  
                fc.Triggers[i].targetObj.SetPage(page);
                this.TriggerBeginSearchEvent(fc.Triggers[i].targetObj);
                fc.Triggers[i].targetObj.DoSearch(this.OnSearchResult);               
            }
        }     
    }
 
    this.PersistSearchCriteria = function()
    {
        var str="";
        
        for (var i=0; i<self.searchControllers.length; i++)
        {
            if (self.searchControllers[i].lastSearchUrl != null)
            {
                str += self.searchControllers[i].name + "{";
                str += self.searchControllers[i].lastSearchUrl.replace(self.searchControllers[i].searchEngineUrl, "" ) + "}"; 
            }
        }
        
        Persister.searchKey.set(encode64(str));
    }

    this.TriggerPersistedSearch = function(encodedString) {

        for (i = 0; i < fc.Triggers.length; i++) {
            this.TriggerBeginSearchEvent(fc.Triggers[i].targetObj);            
        }
        
        var decoded = decode64(encodedString);
        var start = 0;
        var startData;
        var stopData;
        var name;
        var data;

        while (true) {
            startData = decoded.indexOf("{");
            if (startData == -1)
                break;
            stopData = decoded.indexOf("}");
            name = decoded.substring(start, startData);
            data = decoded.substring(startData + 1, stopData);

            for (var i = 0; i < fc.Triggers.length; i++) {
                if (fc.Triggers[i].targetObj.name == name) {
                    fc.Triggers[i].targetObj.DoPersistedSearch(data, self.OnSearchResult);
                    break;
                }
            }
            decoded = decoded.substring(stopData + 1);
        }
    }
    
    // ------------------------------------------------------------------------------
    //  Fresh result from a searchcontroller. Notify all subscribers to this event 
    //  for this searchcontroller.
    // ------------------------------------------------------------------------------
    this.OnSearchResult = function(data, searchcontroller, persistedSearch)
    {
        //debug("Flowcontroller.OnSearchResult() num=" + data.response.numFound + " persistedSearch=" + persistedSearch);

        if (self.searchResultNum > 0)
        {
            self.PersistSearchCriteria();
        }
        self.searchResultNum++;

        for (var i = 0; i < fc.EventSubscriptions.length; i++)
        {
            if ((fc.EventSubscriptions[i].Originator.name == searchcontroller.name) && (fc.EventSubscriptions[i].eventName == "SearchResult"))
            {
                debug("Someone has subscribed to '" + searchcontroller.name + "' to event '" + fc.EventSubscriptions[i].eventName + "'");
                fc.EventSubscriptions[i].method(data, fc.EventSubscriptions[i].subscriberObj);
            }

        }

        
		
		
    } 

	
    
  
}
