///<reference path="CliPropConfig6.js" />
/*  Dependencies:


    getKontikiHosted():                     CliKontikiHosted.js
    loadThisPageInKontikiIfInstalled():     CliKontikiHosted.js
    
*/

function CliController(comPropInstance, profileName, authToken, authSignature, configXml)
{
///<summary>jjjjjjjjj</summary>
///<param name="comPropInstance">Thiasdasdasd </param>

    var _profileName;
    var _authToken;
    var _authSignature;
    var _userName;
    
    var ONLINE_HYBRID_LAUNCH_PAGE = CliBuilOnlineUrl( "/page/hybridLaunch.do?requestedUrl=", true );
        
    /*  The value for the PPV subscription type  */
    var PPV_SUBSCRIPTION_TYPE = 'pay-per-view';
    
    /*  the config xml  */
    var _configXml;
            
   
    /*  an http request used for detecting if online or not  */
    var _xmlHttp;
    
    /*  the com proposition instance  */
    var _propositionInstance;
    /*  an instance of CliKontikiHosted  */
    var _kontikiHosted;
    /*  an instance of CliOeimInstallationFinalisation  */
    var _oeimInstallationFinalisation;
    /*  an instance of CliVideoLibraryActions  */
    var _videoLibraryActions;
    /*  an instance of CliLibraryActions  */
    var _licenseActions;
    /*  an instance of CliLogon  */
    var _logon;
    /*  an instance of CliPageLoader  */
    var _pageLoader;
    /*  an instance of CliPlayerLoader  */
    var _playerLoader;
    /*  an instance of CliTracer  */
    var _tracer;
    
    
    //--------------------------------------------------------------------------------
    //
    // configXml : optional configuration xml.  If present, settings from this xml
    // will override those already stored. If missing, empty settings will be passed
    // to the client core, having no effect.
    //
    CliController.prototype.init = function CliController_initialise(comPropInstance, profileName, authToken, authSignature, configXml)
    {       
        if( configXml == null )
            configXml = "<settings />";
        
        _profileName = profileName;
        _authToken = authToken;
        _authSignature = authSignature;
        _configXml = configXml;
        
        _propositionInstance = comPropInstance;
        _initialisePropositionInstance(_configXml);
        
    }

    //-------------------------------------------------------------------------------
    CliController.prototype.GetJscriptProperty = function( propertyName )
    {
        try
        {
            return this.getKontikiHosted().getKdxApi().pref( "mpod.js." + propertyName );        
        }
        catch( e )
        {
            return null;
        }
    },

    //-------------------------------------------------------------------------------
    CliController.prototype.SetJscriptProperty = function( propertyName, propertyValue )
    {
        this.getKontikiHosted().getKdxApi().pref( "mpod.js." + propertyName ) = propertyValue;        
    },

    //-------------------------------------------------------------------------------
    // fudge method to save adding config to the config xml
    CliController.prototype.SetTestUrl = function( staticContent )
    {
        try { this.getSettings().SetServerStaticContentTestUrl( staticContent ); }catch( e ){}
    }
    
    //-------------------------------------------------------------------------------
    //
    CliController.prototype.ImportMissingMetadata = function()
    {
        var itemsIterator = _propositionInstance.VideoLibraryActions.ListItemsWithoutMetadata();
        
        while( itemsIterator.More )
        {
            this._ImportMissingMetadataForItem( itemsIterator.Current );
            itemsIterator.Next();
        }
    }
    
    //-------------------------------------------------------------------------------
    //
    CliController.prototype._ServerDomain = function()
    {
        return window.location.host;
    }
    
    //-------------------------------------------------------------------------------
    //
    CliController.prototype._ImportMissingMetadataForKdxUrn = function( kdxUrn )
    {
        if (kdxUrn==null) return;
            
        // get the item that relates to the supplied kdxUrn    
	    var libraryItem = this.getPropositionInstance().VideoLibraryActions.GetItem(kdxUrn);
	    if (libraryItem==null) return; 
	    
	    // import the metadata
	    this._ImportMissingMetadataForItem( libraryItem );
    }
    
    //-------------------------------------------------------------------------------
    //
    CliController.prototype._ImportMissingMetadataForItem = function( item )
    {
        if( item.VideoId == null )
            return;
        
        var url = CliBuilOnlineUrl( "/page/videoMetadata.do?videoId=" +
            item.VideoId +
            "&deliveryMethod=dl" +
            "&moid=" + item.MediaContentId );
   
        url = CliCoerceUrlScheme( url );
        iokoAjaxAnywhere.getAJAX( url, 'content' );
    }


    /*  searches through the parent windows to determine if the page has been loaded inside a kontiki template  */
    CliController.prototype.detectIfLoadedInsideKontiki = function() {
        var foundKontiki = false;
        var windowToCheck = window;
        while (1==1) {
            try {
                
                var check = windowToCheck.external.param("authtoken");
                // if code reaches here we are in kontiki
                foundKontiki = true;
            } 
            catch (e) {}
            
            if (windowToCheck == window.top)
                break;
            else
                windowToCheck = window.parent;
        }
        return foundKontiki;
    } 
    
    /*  initialise the proposition instance  */
    function _initialisePropositionInstance(configXml) {
        // we will have a null prop instance if using firefox, so return if null
        if (_propositionInstance==null) return;
        
        // do not initialise if the correct proposition is not installed
        if (!_isInstalled()) return;
       
        // attempt to initialise the com prop instance
        try {
            _propositionInstance.Initialise( _profileName, configXml, _authToken, _authSignature );
        }
        catch (e) {
            if (e.number=="-2146827850") {
                // this error will occur if the user does not have the COM object installed, so we just ignore (assume running in browser)
                return;
            }
            CliDebug( "Clicontroller init failed: " + e.message );
        }
    }
    
     /*  returns a boolean indicating whether sky anytime is installed or not  */
    function _isInstalled () {
        var obj;
        var installed;
        try {
            obj = new ActiveXObject("MPOD.InstalledDetectionObject");
            if (obj != null && obj.PropositionPresent( _profileName ) )
                installed = true;
            else
                installed = false;
        }
        catch (e) {
            installed = false;
        }   
        
        obj = null;
        return installed;
    }
    CliController.prototype.isInstalled = function() {
        return _isInstalled();
    }
    
      
    /* ----------------------------------------------- */
    /*               public accessors                    */
    /* ----------------------------------------------- */
    
    //----------------------------------------------------------------------
    CliController.prototype.getSettings = function()
    {
        var propInstance = this.getPropositionInstance();
        var settings = propInstance.Settings;
        
        return settings;
    }
    
    /*  Return the proposition instance */
    CliController.prototype.getPropositionInstance = function()
    {
        if( _propositionInstance==null )
        {
            _initialisePropositionInstance(_configXml);
        }
        
        return _propositionInstance;
    }
    
    /*  Return the instance of CliKontikiHosted  */
    CliController.prototype.getKontikiHosted = function() {
        if (_kontikiHosted==null) {
            var controller = this;
            var propInstance = this.getPropositionInstance();
            _kontikiHosted = new CliKontikiHosted(controller, propInstance, _profileName, _authToken, _authSignature); 
        }
        return _kontikiHosted;
    } 
    
    /*  Return the instance of CliVideoLibraryActions  */
    CliController.prototype.getVideoLibraryActions= function(mediaContentId) {
        if (_videoLibraryActions==null || _videoLibraryActions.getMediaContentId()!=mediaContentId ) {
            var self = this;
            _videoLibraryActions = new CliVideoLibraryActions(self, mediaContentId); 
        }
        return _videoLibraryActions;
    }  
    
    /*  Return the instance of CliLicense  */
    CliController.prototype.getLicenseActions = function() {
        if (_licenseActions==null ) {
            _licenseActions = new CliLicenseActions(); 
        }
        return _licenseActions;
    }     
    
    /*  Return the instance of CliLogon  */
    CliController.prototype.getLogon = function() {
        if (_logon==null) {
            var propInstance = this.getPropositionInstance();
            var licenseActions = this.getLicenseActions();
            _logon = new CliLogon(propInstance, licenseActions); 
        }
        return _logon;
    }  
    
    /*  Return the instance of CliPageLoader  */
    CliController.prototype.getPageLoader = function() {
        if (_pageLoader==null) {
            var self = this;
            _pageLoader = new CliPageLoader(self); 
        }
        return _pageLoader;
    }  
    
    /*  return the tracer  */
    CliController.prototype.getTracer = function() {
        if (_tracer==null) {
            var propInstance = this.getPropositionInstance();
            _tracer = new CliTracer(propInstance, document.location.href);
        }
        return _tracer;
    }
    
          
  
    /* ----------------------------------------------- */
    /*     online / offline methods and app start      */
    /* ----------------------------------------------- */
    
    /*  loads the application  */
    CliController.prototype.AppStart = function() {

        var self = this;
        // set up the delegates to load the relevant pages depending on whether we are online or offline
		var hasSettings = this._settingsPresent();  
        var processAsOnline = function() {
            // force checking of deliveries
            self.getKontikiHosted().getKdxApi().checkForDeliveries();
            // if online load the online home page
            self.getKontikiHosted().launchOnlineHomePage();
        };
        var processAsOffline = function() {
            if (hasSettings) {
                // we are offline, so start checking for online connectivity
                //self.getPropositionInstance().Offline.StartCheckingForReturnToOnline();
                // we have settings so load the offline library
                self.getKontikiHosted().launchOfflineLibrary();
            }
            else {
                // cannot locate settings, so display an appropriate page
                self.getKontikiHosted().launchMissingSettingsPage();
            }
        };
        
        // perform the initial online check using the ping method rather than the page loader
        if (!hasSettings)
            this._forceInitialSettings();
        var isOnline = _propositionInstance.Offline.CheckIsOnline('');
        if (isOnline)
            processAsOnline();
        else
            processAsOffline();
    }
    
    /*
        forces initial settings by reinitialising the proposition config with default settings
    */
    CliController.prototype._forceInitialSettings = function() {
        var _defaultSettings = '<settings>'+
            '  <initialisation-settings>'+
            '    <mpod-server>https://anytimepc-client.sky.com/vod</mpod-server>'+
            '      <channels>'+     
            '        <channel name="SKYMOVIES" display-name="Movies">'+
            '          <max-bookmarks>50</max-bookmarks>'+
            '          <max-downloads>20</max-downloads>'+
            '          <pin-protected>false</pin-protected>'+
            '          <title-display-name>Title</title-display-name>'+
            '          <secondary-title-display-name>Genre</secondary-title-display-name>'+
            '        </channel>'+
            '        <channel name="SKYSPORTS" display-name="Sports">'+
            '          <max-bookmarks>50</max-bookmarks>'+
            '          <max-downloads>20</max-downloads>'+
            '          <pin-protected>false</pin-protected>'+
            '          <title-display-name>Title</title-display-name>'+
            '          <secondary-title-display-name>Genre</secondary-title-display-name>'+
            '        </channel>'+
            '        <channel name="SKYENTERTAINMENT" display-name="Entertainment">'+
            '          <max-bookmarks>50</max-bookmarks>'+
            '          <max-downloads>20</max-downloads>'+
            '          <pin-protected>false</pin-protected>'+
            '          <title-display-name>Programme</title-display-name>'+
            '          <secondary-title-display-name>Episode</secondary-title-display-name>'+
            '        </channel>'+
            '        <channel name="SKYCULTURE" display-name="Lifestyle &amp; Culture">'+
            '          <max-bookmarks>50</max-bookmarks>'+
            '          <max-downloads>20</max-downloads>'+
            '          <pin-protected>false</pin-protected>'+
            '          <title-display-name>Title</title-display-name>'+
            '          <secondary-title-display-name>Genre</secondary-title-display-name>'+
            '        </channel>'+                                                                                               
            '      </channels>'+
            '    </initialisation-settings>'+
            '  <tracing level="verbose" />'+
            '</settings>';

        _initialisePropositionInstance(_defaultSettings);
        
        this.SetTestUrl('https://anytimepc.sky.com/drm.jpg');
        
    }

    
    /*
        Responsible for checking if there are any settings present within the offline application
        returns a bool, if there are settings present true will be returned otherwise false.
        This accepts an instantiated com proposition to check
    */
    CliController.prototype._settingsPresent = function()
    {
        try
        {
            //attempt to get the propositions settings
            if(_propositionInstance.Settings == null)
            {
               //settings are not present return false
                return false;
            }
        }
        catch (excep)
        {
            //Error occured getting the settings therefore they have not been set so return false
            return false;
        }
        var chanIterator;
        try
        {
            //attempt to get the channels from the client controller
            chanIterator = this.getChannels();
        }
        catch (excep)
        {
            //failed to get channels therefore there is an issue with the settings return false
            return false;
        }
            
        if (!chanIterator.More)
        {
           //there are no channels set. Therefore settings are not in place
           return false;
        }
        
        //Still here so channels are present and set, therefore as per discussions settings are present 
        return true;
    }
 

	//--------------------------------------------------------------------------------
	// compile statistics for the library as it currently stands
	//
	CliController.prototype.CompileStatistics = function ()
	{
		var prop = this.getPropositionInstance();
        var stats = prop.VideoLibraryActions.CompileLibraryStatistics();
        return stats;
	}
	
    /* ----------------------------------------------- */
    
    
	// checks that the installation has been finalised.  if it hasn't, it starts the process
	CliController.prototype.installIsFinalised = function() {
	    if (getOeimInstallationFinalisation().isFinalised()) 
	        return true;
	    getOeimInstallationFinalisation().processFinalisation();   
	}
	
	//--------------------------------------------------------------------------------
	CliController.prototype.SplitUrl = function( urlStr )
    {
        var uri = new Object();
        
        var i = urlStr.indexOf( ":" );
        
        if( i > 0 )
        {
            uri.Scheme = urlStr.substring( 0, i + 3 ).toLowerCase();
        }
        else
        {
            uri.Scheme = null;
            i = 1;
        }
        
        var j = urlStr.indexOf( ":", i + 3 );
        
        if( j == -1 )
        {
            j = urlStr.indexOf( "/", i + 3 );
        }
        
        if( j > 0 )
        {
            uri.Domain = urlStr.substring( j, i + 3 ).toLowerCase();
            uri.PostDomain = urlStr.substring( urlStr.length, j );
        }
        else
        {
            uri.Domain = urlStr.substring( urlStr.length, i + 3 ).toLowerCase();
            uri.PostDomain = "";
        }
        
        return uri;
    }
	
	//--------------------------------------------------------------------------------
    CliController.prototype.DomainsMatchIgnoreScheme = function( urlStrX, urlStrY )
    {
        ///<summary></summary>
        
        var urlX = this.SplitUrl( urlStrX );
        var urlY = this.SplitUrl( urlStrY );

        return urlX.Domain == urlY.Domain;
    }

	/*  returns true if the url of the current page is in the same domain and url of the pages to be hosted inside the client  */
    CliController.prototype.isClientPageUrl = function(url) {
        
        var dom = this.getCurrentDomainFromUrl(url);
        var clientDomain = CliGetClientDomain();

        return (dom==clientDomain);        
    }
	    
	/*  returns true if the url of the current page is in the same domain and url of the browser specific pages   */
    CliController.prototype.isBrowserPageUrl = function(url) {
        
        var dom = this.getCurrentDomainFromUrl(url);
        var browserDomain = CliGetBrowserDomain();

        return (dom==browserDomain);        
    }
    
    /*  if a browser url has been launched, and the client is installed, the client domain is loaded  */
    CliController.prototype.switchDomainIfNecessary = function( url )
    {
		if( url.indexOf( ONLINE_HYBRID_LAUNCH_PAGE ) >= 0 )
            return;
            
        // if we are not in either the client or browser domain, the exit from this function.  this will happen if
        // we are in the preview domian
        var inClientDomain  = this.DomainsMatchIgnoreScheme( url, CliGetClientDomain() ); // this.isClientPageUrl( url );
        var inBrowserDomain = this.DomainsMatchIgnoreScheme( url, CliGetBrowserDomain() );// this.isBrowserPageUrl( url );
        
        if( !inClientDomain && !inBrowserDomain )
            return;        

        var clientDomain    = CliGetClientDomain();
        var browserDomain   = CliGetBrowserDomain();

        if( this.detectIfLoadedInsideKontiki() )
        {
            if( !inClientDomain )
            {
                // in the client but not the client domain, so switch to the client domain
				window.HEAnextLoc =  this.CoerceUrlIntoClientDomain( url );
				// AN ERROR OCCURRS IN THE CLIENT BECAUSE OF A TIMEOUT - jQuery?
				// AS THIS RELOADS THE PAGE - EITHER IGNORE THE ERROR OR ADD A
				// MINOR DELAY TO ALLOW TIMEOUTS TO TAKE PLACE.
				window.setTimeout(function(){
					document.location.href = window.HEAnextLoc;
				},50);
            }    
        }
        else
        {
            //var isInstalled     = _isInstalled();
            
            if( !inBrowserDomain )
            //{
            //    if( isInstalled )
            //    {
            //        // in the browser, in the browser domain, but we have the client installed, so launch in the client
            //        var urlToLaunch = ONLINE_HYBRID_LAUNCH_PAGE + encodeURIComponent( document.location.href );
            //        document.location.href = urlToLaunch;
            //    }
            //}
            //else
            {
                // in the browser, but in the client domain, so switch to the browser domain
				window.HEAnextLoc =  this.CoerceUrlIntoBrowserDomain( url );
				// AN ERROR OCCURRS IN THE CLIENT BECAUSE OF A TIMEOUT - jQuery?
				// AS THIS RELOADS THE PAGE - EITHER IGNORE THE ERROR OR ADD A
				// MINOR DELAY TO ALLOW TIMEOUTS TO TAKE PLACE.
				window.setTimeout(function(){
					document.location.href = window.HEAnextLoc;
				},50);
            }
        }
    }
    
    //--------------------------------------------------------------------------------
    CliController.prototype.CoerceUrlIntoClientDomain = function( sourceUrl )
    {
        var splitUrl = this.SplitUrl( sourceUrl );
        
        return CliGetClientDomain() + splitUrl.PostDomain;
    }

    //--------------------------------------------------------------------------------
    CliController.prototype.CoerceUrlIntoBrowserDomain = function( sourceUrl )
    {
        var splitUrl = this.SplitUrl( sourceUrl );
        
        return CliGetBrowserDomain() + splitUrl.PostDomain;
    }
    
    /*  returns the domain from the current url  
    */
    CliController.prototype.getCurrentDomain = function()
    {
        return document.location.protocol + "//" + document.location.host;
        //return this.getCurrentDomainFromUrl( document.location.href);
    }
    
    /*  returns the domain from a url  *
        Parameters:
            url     : The url to extract the domain from
    */
    CliController.prototype.getCurrentDomainFromUrl = function(url) {
        var uri = new Object();
        _getURL(uri);
        return uri.protocol + uri.dom;  
    }
    
    //TODO:  Strip out what we don't need
    // Current Page Reference
    // copyright Stephen Chapman, 1st Jan 2005
    function _getURL(uri) {
        uri.dir = location.href.substring(0, location.href.lastIndexOf('\/'));
        uri.dom = uri.dir; 
        
        if (uri.dom.substr(0,7) == 'http:\/\/') {
            uri.protocol = 'http:\/\/';
            uri.dom = uri.dom.substr(7);
        }
        else if (uri.dom.substr(0,8) == 'https:\/\/') {
            uri.protocol = 'https:\/\/';
            uri.dom = uri.dom.substr(8);
        }
        
        uri.path = ''; 
        var pos = uri.dom.indexOf('\/'); 
        if (pos > -1) {
            uri.path = uri.dom.substr(pos+1); 
            uri.dom = uri.dom.substr(0,pos);
        }
        uri.page = location.href.substring(uri.dir.length+1, location.href.length+1);
        pos = uri.page.indexOf('?');
        if (pos > -1) {
            uri.page = uri.page.substring(0, pos);
        }
        pos = uri.page.indexOf('#');
        if (pos > -1) {
            uri.page = uri.page.substring(0, pos);
        }
        uri.ext = ''; 
        pos = uri.page.indexOf('.');
        if (pos > -1) {
            uri.ext =uri.page.substring(pos+1); 
            uri.page = uri.page.substr(0,pos);
        }
        uri.file = uri.page;
        if (uri.ext != '') 
            uri.file += '.' + uri.ext;
        if (uri.file == '') 
            uri.page = 'index';
        uri.args = location.search.substr(1).split("?");
        
        return uri;
    }
    
    
    /*  if the page is not already loaded inside a kontiki template, an attempt is made to load it inside one.
        if the page is already loaded in kontiki, then we do not have to do anything else as the page will be
        navigated to as normal  */
    CliController.prototype.loadThisPageInKontikiIfInstalled = function()
    {
        this.loadPageInKontikiIfInstalled(document.URL);
    }
    /*  if the page is not already loaded inside a kontiki template, an attempt is made to load it inside one.
        if the page is already loaded in kontiki, then we do not have to do anything else as the page will be
        navigated to as normal  */
    CliController.prototype.loadPageInKontikiIfInstalled = function(url) {
        var alreadyLoadedInKontiki = this.detectIfLoadedInsideKontiki();
        //if (!alreadyLoadedInKontiki) {
            var launchedInKontiki = this.getKontikiHosted().launchInKontikiIfAvailable( url );
        //}
    }
    
    /*  loads a url in kontiki.  if in the client and online the page is loaded inside a kdxsecureframe.  
        if in the client but offline, the offline library from the cache is loaded inside a kdxsecureframe.  
        if the url is not from the client, no action is taken.  this function should be called from the 
        onclick event of an anchor so that if no action is taken the original href is loaded.  */
	CliController.prototype.loadUrl = function (href) {
		
		try {show_waiting();}catch(e){}
		try {
			if (this.isClientPageUrl(href)) {
				this.getPageLoader().load(href);
				return false;
		    }
		}
		catch (e) { 
		    return true; 
		}
		return true;
	}
    
    /*  loads a url in kontiki.  if in the client and online the page is loaded inside a kdxsecureframe.  
        if in the client but offline, the offline library from the cache is loaded inside a kdxsecureframe.  
        if the url is not from the client, no action is taken.  this function should be called from the 
        onclick event of an anchor so that if no action is taken the original href is loaded.  */
	CliController.prototype.loadUrlWithDelegates = function (onlineDelegate, offlineDelegate) {
		try {
			this.getPageLoader().loadWithDelegates(onlineDelegate, offlineDelegate);
			return false;
		}
		catch (e) { 
		    return true; 
		}
		return true;
	}
    
    /*  loads an item in the player.  if in the client and online, the online player is loaded in a seperate 
        kdxsecureframe.  if in the client but offline, the offline player from the cache is loaded 
        inside a kdxsecureframe.  this function
        should be called from the onclick event of an anchor so that if no action is taken the original
        href is loaded.  
        Note:   The original behaviour of this method was that the document.location.href must be a
                client page url.  This restriction has been removed as the code also needs to be called
                from the offline library in the local kontiki store.
        
    */
	CliController.prototype.playKdxUrn = function (kdxUrn) {
		try {	
		    // get the item 
		    var libraryItem = this.getPropositionInstance().VideoLibraryActions.GetItem(kdxUrn);
		    if (libraryItem==null) return;
		    
		    // check that we have a license for the item
		    var licensed;
		    //if (libraryItem.SubscriptionType==PPV_SUBSCRIPTION_TYPE) {
		        // if PPV always assume we got a license, even if it has expired so that we can display the no license message in the offline media player (as per GP)
		        //licensed = true;
		    //}
		    if (libraryItem.LicenceExpiryDate < new Date()) {
		        licensed = false;
		    }
		    else {
		        licensed = true;
		    }
		        		        

	        // if online and have a license, play the content using the offline player.  if online but have
	        // no license, then play using the online player.  if not online always play using the offline player.
	        var self = this;
	        var online = function() {
	            if (licensed) {
	                // if we have a license, play the content in the offline player
	                self.getKontikiHosted().launchOfflineMediaPlayer(kdxUrn);
	            }
	            else {
	                var onlinePlayerUrl = CliGetClientDomain() + libraryItem.OnlinePlayerUrl;
	                self.getKontikiHosted().launchOnlineMediaPlayer(kdxUrn, onlinePlayerUrl);
	            }
	        };
	        var offline = function() {
                //self.getPropositionInstance().Offline.StartCheckingForReturnToOnline();
	            self.getKontikiHosted().launchOfflineMediaPlayer(kdxUrn);
	        };
	        this.getPageLoader().loadWithDelegates( online, offline);
		        
		    // return false to prevent the anchor from posting back
			return false;
		}
		catch (e) { 
		    return true; 
		}
		return true;
	}
    
    
   
    /*  obtain an iterator that allows access to filtered library items  */
    //
    // channel: the channel to list data for
    // downloadTypeExclusionFilter: comma seperated list of download types to exclude
    //
    CliController.prototype.getLibraryItems = function( channel, downloadTypeExclusionFilter ) // : IVideoLibraryIterator
    {
        var prop = this.getPropositionInstance();
        var iterator = prop.VideoLibraryActions.ListLibrary( channel, downloadTypeExclusionFilter );
        return iterator;
    }
    
    /*  obtain an iterator that allows access to a list of channels  */
    CliController.prototype.getChannels = function() // : IChannelListIterator
    {
        var prop = this.getPropositionInstance();
        var iterator = prop.Settings.Channels;
        return iterator;
    }
    
    /*  To be called when a new item has been loaded by kontiki.  Imports missing metadata.
        Parameters:
           kdxUrn            : A kdxUrn of a new item
    */
    CliController.prototype.newItem = function(kdxUrn) {
        
        this._ImportMissingMetadataForKdxUrn(kdxUrn);
    }
    
//    /*  To be called when an item's state has changed in kontiki.  Checks that metadata is required and imports if necessary.
//        Parameters:
//           kdxUrn            : A kdxUrn of the item
//    */
//    CliController.prototype.progressItem = function(kdxUrn) {
//        if (kdxUrn==null) return;
//        
//        var libraryItem = this.getPropositionInstance().VideoLibraryActions.GetItem(kdxUrn);
//        if (libraryItem==null) return;
//        
//        var startMeta = item.MetadataVersion;
//        if( startMeta == null || ( startMeta.substring( 4,5 ) != 'c' && startMeta.substring( 4,5 ) != 'p' ) ) {
//            // we have part metadata
//            this._ImportMissingMetadataForItem(libraryItem);
//        }
//    }
    
    /*  Calls 'complete download' on the server for all items requiring it
    */
    CliController.prototype.completeItem = function( videoId, purchaseRef, kdxUrn )
    {
        if (!this.isLoggedIn()) 
            return;
        
        if( videoId == null || videoId == '' ) return;
        if( purchaseRef == null || purchaseRef == '' ) return;
        if( kdxUrn == null || kdxUrn == '' ) return;
        
        var items = videoId + "|" + purchaseRef + "|" + kdxUrn;
        
        var url = this.getCurrentDomain() + CliGetAppRoot() +
        "/page/completeDownload.do?items=" +
        items;

        url = CliCoerceUrlScheme( url );   
        iokoAjaxAnywhere.getAJAX( url, 'content' );
    }

    CliController.prototype.completeItemById = function( kdxUrn )
    {
        var item = this.getVideoLibraryActions( kdxUrn ).GetItem();
        
        if( item != null )
        {
            this.completeItem( item.VideoId, item.PurchaseReference, kdxUrn );
        }
    }
    
    //--------------------------------------------------------------------------------
    //
    CliController.prototype.serverCancelDownload = function( videoId, purchaseReference )
    {
        show_waiting();
        
        var itemString = videoId + "|" + purchaseReference;
        
        var url = this.getCurrentDomain() + CliGetAppRoot() +
        "/page/cancelDownload.do?items=" +
        itemString;

        url = CliCoerceUrlScheme( url );   
        iokoAjaxAnywhere.getAJAX( url, 'content' );
    }
    
    
    /* ----------------------------------------------- */
    /*          username related                       */
    /* ----------------------------------------------- */
    CliController.prototype.getUserName = function() { return _userName;}
    CliController.prototype.setUserName = function(userName) { _userName = userName;}
    CliController.prototype.isLoggedIn = function() { 
        return !(_userName==null || _userName=='');
    }
        
    
  
    /* ----------------------------------------------- */
    /*          invoke the constructor                 */
    /* ----------------------------------------------- */
    this.init(comPropInstance, profileName, authToken, authSignature, configXml);
    return true;
}
