﻿///<reference path="MicrosoftAjax.debug.js" 
///<reference path="control.js" 


var $delegate = Function.createDelegate ; 


Type.registerNamespace("SLx");


SLx.Application = function ( host ) 
{ 
    this._host = host ;     
    Sys.Debug.assert ( SLx.Application.Current == null , "Application shouldbe initialized once" , true ); 
      
    SLx.Application.Current = this;  
    
    this._templates = new Array(); 
    this._resources = new SLx.ResourceDictionary(); 
    this._downloaders =  [] ; 
    this._layoutManager = new SLx.LayoutManager (); 
      
} 



SLx.Application.Current = null ; 
SLx.Application.prototype = 
{ 
    createDownloader : function SLx$Application$createDownloader ( ) 
    { 
        var downloader = this.get_host().createObject( "downloader" );     
        return downloader; 
    }, 
    
    get_host : function SLx$Application$get_host() 
    { 
        return this._host;         
    }, 
    
    _id : 0 , 
    
    get_nextUniqueId : function () 
    { 
        this._id++ ; 
        return this._id.toString(); 
    }, 
     
    createUniqueElement : function SLx$Application$createUniqueElement (  strxaml ) 
    { 
        if ( strxaml == null || strxaml == "" ) 
        { 
            strxaml = "<Canvas xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' x:Name='{0}' />" ; 
        }  
        
        strxaml = strxaml.replace ( "{0}" , this.get_nextUniqueId () );    
         
        return this.createElement ( strxaml, false );      
    }, 
    
    createText: function SLx$Application$createText ( text ) 
    { 
        var tb = this.createElement ( "<TextBlock />" ); 
        tb.Text = text ; 
        return tb;          
    }, 
    
    createElement : function SLx$Application$createElement ( template , useNamescope ) 
    { 
        if ( useNamescope == undefined ) 
        { 
            useNamescope = SLx.ResourceDictionary.DefaultScopeVisibility ; 
        } 
        return this._host.content.createFromXaml ( template, useNamescope); 
    }, 
       
    get_resources : function SLx$Application$get_resources () 
    { 
        return this._resources ; 
    }, 
    
    //TODO: refactor and hide this.. 
    get_downloaders : function SLx$Application$get_downloaders () 
    { 
        return this._downloaders; 
    },  
    
    get_layoutManager : function SLx$Application$get_layoutManager () 
    { 
        return this._layoutManager ; 
        
    } , 
    
    get_cacheLayout : function ( ) 
    { 
        return true; 
    }, 
    
    _systemId : 0 , 
    get_UniqueSystemId  : function ( ) 
    { 
        return ++this._systemId ; 
    }, 
    
    beginInit : function  ( ) 
    { 
    
    }, 
    
    endInit : function () 
    { 
    
    },  
    
    add_initCompleted : function  ( callback )  
    { 
    
    } 
}  


SLx.DragDropManager = function () 
{ 


}


SLx.ResourceDictionary = function () 
{   
    this._resources = [];  
}

SLx.ResourceDictionary.DefaultScopeVisibility = false; 

SLx.ResourceDictionary.prototype= 
{ 
    add : function SLx$ResourceDictionary$add ( name, value ) 
    { 
        this._resources[name] = value ; 
    }, 
    
    findName : function  SLx$ResourceDictionary$findName ( name ) 
    { 
        var ret = this._resources[name]; 
        if ( ret == null ) 
        { 
            var downloaders = SLx.Application.get_downloaders(); 
            for ( var i = 0 ; i < downloaders.length ; i++ ) 
            { 
                ret =  downloaders[i].getResponseText( SLx.Constants.makeXAMLPath ( name ));  
                if ( ret != null ) 
                    break;                             
            } 
        } 
        return ret; 
    }, 
    
    cloneName : function SLx$ResourceDictionary$cloneName ( name , newnamescope) 
    { 
        var xaml = this._resources[name]; 
        if ( xaml != null ) 
        { 
            if( newnamescope == undefined ) 
                newnamescope = SLx.ResourceDictionary.DefaultScopeVisibility ;             
             var object = SLx.Application.Current.get_host().content.createFromXaml (  xaml , newnamescope ); 
             return object ; 
        }        
        return null ;               
    },  
    
    clear : function  SLx$ResourceDictionary$clear ( ) 
    { 
           //TODO: 
           Error.notImplemented ( "TODO") ; 
    }, 
    
    get_count:  function SLx$ResourceDictionary$get_count ( ) 
    { 
        this._resources.length ;     
    }, 
    
    dispose : function ( ) 
    { 
        
        delete this._resources;     
    }  

}; 
 

SLx.ResourceDownloader  = function () 
{ 
    this._isDownloading = false; 
    this._downloader = null ; 
} 

SLx.ResourceDownloader.prototype = 
{ 

    StartDownload : function SLx$ResourceDownloader$StartDownload ( xamlpath , completedCallback , progressCallback , failedCallback )
    { 
        Sys.Debug.assert ( !this._isDownloading , "can not have a downloader download two files in parallel" ) ; 
        
        this._downloader = SLx.Application.Current.createDownloader();         
        this._downloader.addEventListener("DownloadProgressChanged", $delegate (this, this._onDownloadProgressChanged));
        this._downloader.addEventListener("Completed", $delegate(this, this._onDownloadCompleted));
        this._downloader.addEventListener("DownloadFailed", $delegate (this, this._onDownloadFailed));
        this._downloader.open("GET", xamlpath );
        
        this._onCompleted = completedCallback  ; 
        this._onProgress = progressCallback ; 
        this._onFailedCallback = failedCallback ; 
        
        
        this._isDownloading = true ; 
        this._downloader.send();
        
    },  
    
    
    _onDownloadProgressChanged : function SLx$ResourceDownloader$_onDownloaderProgressChanged ( sender , args ) 
    { 
        Sys.Debug.trace ( "_onDownloadProgressChanged" ); 
    } , 
    
    _onDownloadFailed : function SLx$ResourceDownloader$_onDownloaderProgressChanged ( sender , args ) 
    { 
        Sys.Debug.trace ( "_onDownloadFailed" ); 
        this._isDownloading = false ; 
        if ( this._onFailed != null ) 
        { 
            this._onFailed ( sender , args ); 
        } 
    }, 
 
    _onDownloadCompleted : function SLx$ResourceDownloader$_onDownloaderProgressChanged ( sender , args ) 
    { 
        Sys.Debug.trace ("_onDownloadCompleted"); 
        this._isDownloading = false ; 
        if ( this._onCompleted != null ) 
        { 
            this._onCompleted ( sender , args ) ; 
        }         
    }   
}


SLx.VerticalAlignment = function () { throw Error.notImplemented( "Enum" ); } 
SLx.VerticalAlignment.Top          = 0 ; 
SLx.VerticalAlignment.Bottom       = 1 ; 
SLx.VerticalAlignment.Center       = 2 ; 
SLx.VerticalAlignment.Stretch      = 3 ; 


SLx.HorizontalAlignment = function()  { throw Error.notImplemented ("Enum" ); } 
SLx.HorizontalAlignment.Left       = 0 ; 
SLx.HorizontalAlignment.Right      = 1 ; 
SLx.HorizontalAlignment.Center     = 2 ; 
SLx.HorizontalAlignment.Stretch    = 3 ; 


SLx.TextDecorations = function () { throw Error.notImplemented ("Enum"); } 
SLx.TextDecorations.Underline = "Underline" ; 
SLx.TextDecorations.None = "None" ; 

 
SLx.Visibility = function () { throw Error.notImplemented ("Enum" ); } 
SLx.Visibility.Collapsed = "Collapsed" ; 
SLx.Visibility.Visible = "Visible" ; 


SLx.Constants = function () { throw Error.notImplemented("Constants"); } 
SLx.Constants.Expander = "Expander" ; 
SLx.Constants.Button = "Button" ;  
SLx.Constants.Label = "Label" ; 
SLx.Constants.CheckBox = "CheckBox" ; 
SLx.Constants.TextEdit = "TextEdit" ; 
SLx.Constants.RepeatButton = "RepeatButton" ; 
SLx.Constants.Scrollbar = "Scrollbar" ; 
SLx.Constants.HorizontalScrollbar = "HorizontalScrollbar" ; 
SLx.Constants.Hyperlink = "Hyperlink" ; 
SLx.Constants.Expander = "Expander" ; 
SLx.Constants.Radio = "Radio" ; 
SLx.Constants.Slider= "Slider" ; 
SLx.Constants.ComboBox = "ComboBox" ; 
SLx.Constants.WrapPanel = "WrapPanel" ; 



SLx.Dock = function () { throw Error.notImplemented("Enum");  } 
SLx.Dock.Left  = 0 ; 
SLx.Dock.Right = 1; 
SLx.Dock.Top = 2 ;  
SLx.Dock.Bottom = 3 ; 
SLx.Dock.Fill = 4; 


SLx.Constants.makeXAMLPath = function SLx$Constants$makeXAMLPath  ( uri ) 
{ 
    return uri + ".xaml" ; 
} 

SLx.Constants.makePackagePath = function SLx$Constants$makeXAMLPath  ( uri ) 
{ 
    return uri + ".zip" ; 
} 


SLx.Constants.removeXAMLPath = function ( name ) 
{ 
    if ( name.endsWith ( ".xaml" ) ) 
    { 
        return name.replace ( ".xaml" ,  "") ; 
    }  
    
    return name ; 
}  


SLx.Size = function ( x  , y ) 
{ 
    this.Width = x; 
    this.Height  = y; 
} 

SLx.Size.prototype = 
{ 
    set_width :  function  ( value ) { this.Width = value ; } ,
    get_width : function () {  return this.Width  ; } ,
    
    set_height :  function  ( value ) { this.Height = value ; }, 
    get_height : function () {  return this.Height  ; } , 
    
    
    toString : function ()  
    { 
        return "Size: " + this.Width.toString() + "," + this.Height.toString(); 
    } 
} 


SLx.Orientation = function ( ) 
{ 
    Error.notImplemented ( "Enum"); 
} 

SLx.Orientation.Vertical = 0 ; 
SLx.Orientation.Horizontal = 1 ; 


SLx.ILayout = function  SLx$ILayout () 
{ 
    throw Error.notImplemented () ; 
} 

SLx.ILayout.prototype = 
{ 
    measure  : function SLx$ILayout$measure ( width, height ) 
    { 
        throw Error.notImplemented("ILayout") ; 
    }, 

    arrange : function SLx$ILayout$arrange ( left, top , width , height ) 
    { 
        throw Error.notImplemented("ILayout") ; 
    } , 

    get_desiredSize  : function SLx$ILayout$get_desiredSize () 
    { 
        throw Error.notImplemented("ILayout") ; 
    } , 
    
    updateLayout : function SLx$ILayout$updateLayout () 
    { 
        throw Error.notImplemented("ILayout"); 
    } 
    
} 

SLx.ILayout.registerInterface ( 'SLx.ILayout'); 


 SLx.LayoutHelper = function ( ) 
 { 
    throw Error.notImplemented ( "STATIC CLASS"); 
 } 
 
 
 SLx.LayoutHelper.Arrange = function SLx$LayoutHelper$Arrange (  item , left, top, width , height ) 
 { 
    Sys.Debug.assert ( item != null ) ; 
    
    if ( left != null ) 
        item["Canvas.Left"] = left; 
    if ( top != null ) 
        item["Canvas.Top"] = top; 
    if ( width != null ) 
        item.width = width ; 
    if ( height != null ) 
        item.height = height ; 
 } 
 
 SLx.Thickness = function ( left, top ,right , bottom ) 
 { 
   this.Left = left; 
   this.Top = top ; 
   this.Right = right ; 
   this.Bottom = bottom; 
 }
 
 
 SLx.VisualTreeHelper = function () 
 { 
        Error.notImplemented( "Intending for this to be static"); 
 } 
 
SLx.VisualTreeHelper.reParent =  function ( visual, newparent  ) 
{ 
    var parent = visual.getParent (); 
    var ok = false; 
    if ( parent != null ) 
    { 
        if (!parent.Equals ( newparent) ) 
        { 
            parent.Children.remove ( visual ); 
            // TODO failure 
            ok =  ( newparent.Children.add ( visual )!= null ) ; 
            if ( ok ) 
            { 
                visual["Canvas.Left"] = 0 ; 
                visual["Canvas.Top"] = 0 ;                 
            } 
        }  
        else 
            ok = true ;                 
    } 
    else
    { 
        // TODO... try catch .. 
         ok =  ( newparent.Children.add ( visual )!= null ) ; 
    } 
    return ok ; 
    
}

SLx.VisualTreeHelper.arrangeContent = function ( content, parent ) 
{ 
    if ( content!= null && SLx.VisualTreeHelper.NeedsAlignment( content ) ) 
    {
        var verAlignment = content.get_verticalAlignment(); 
        var horAlignment = content.get_horizontalAlignment (); 
        var top = 0 ; 
        var size = content.get_desiredSize(); 
        
        if ( horAlignment == SLx.HorizontalAlignment.Center ) 
        { 
            left = ( parent.get_width() - size.Width )/2 ;                  
        } 
        else if ( horAlignment == SLx.HorizontalAlignment.Right ) 
            left =  parent.get_width() - size.Width  ; 
        else 
            left = 0 ; 
            
        if ( verAlignment == SLx.VerticalAlignment.Center ) 
        { 
            top = ( parent.get_height() - size.Height )/2 ;                  
        } 
        else if ( verAlignment == SLx.VerticalAlignment.Right ) 
            top=   (parent.get_height() - size.Height )  ; 
        else 
            top = 0 ; 
            
        content.arrange ( left, top, size.Width , size.Height );     
    }
    
}

SLx.VisualTreeHelper.NeedsAlignment = function ( item ) 
{ 
    if( SLx.VisualTreeHelper.isControl ( item )) 
    { 
        var hal = item.get_horizontalAlignment (); 
        var val = item.get_verticalAlignment (); 
        if ( hal != SLx.HorizontalAlignment.Left  || 
             val != SLx.VerticalAlignment.Top  || 
             Object.getType(item).inheritsFrom ( SLx.Panel) )
        {  
             return true ;      
        } 
    } 
    return false; 
} 

SLx.VisualTreeHelper.isValidSize = function (  size )
{ 
    if ( size == null ) 
        return false ; 
    if  ( size.Width == -1 || size.Height == -1 ) 
        return false; 
    
    return true; 
}  


SLx.VisualTreeHelper.GetAlignment = function  ( item , parent, dohorizontal, dovertical ) 
{
    var result = { left: 0 , top: 0 };     
    if ( item != null && item.get_visual().Tag  != null ) 
    {
        var verAlignment = item.get_verticalAlignment(); 
        var horAlignment = item.get_horizontalAlignment (); 
        
        var itemSize = item.get_desiredSize(); 
        if ( dohorizontal ) 
        { 
            if ( horAlignment == SLx.HorizontalAlignment.Center ) 
            { 
                result.left = ( parent.get_width() - itemSize.Width )/2 ;                  
            } 
            else if ( horAlignment == SLx.HorizontalAlignment.Right ) 
                result.left =  parent.get_width() - itemSize.Width ; 
            /* else 
                restult.left = 0 ; */ 
        } 
        if ( dovertical ) 
        {                 
            if ( verAlignment == SLx.VerticalAlignment.Center ) 
            { 
                result.top = ( parent.get_height() - itemSize.Height )/2 ;                  
            } 
            else if ( verAlignment == SLx.VerticalAlignment.Bottom ) 
                result.top=   (parent.get_height() - itemSize.Height )  ; 
            /* else 
                result.top = 0 ;  */ 
         }         
    }   
    
    return result ; 
    
    
}
            

SLx.VisualTreeHelper.findBrowserPosition = function ( visual  ) 
{ 
    var result = SLx.VisualTreeHelper.GetOffsetFromRoot ( visual  );  

    var element = SLx.Application.Current.get_host().parentNode;
    while (element && element.tagName != "BODY") {
        result.left += element.offsetLeft;
        result.top += element.offsetTop;
        element = element.parentNode;
    }
    return result;
 } 

SLx.VisualTreeHelper.GetOffsetFromRoot = function ( visual  ) 
{ 
    var result = {left: visual["Canvas.Left"], top: visual["Canvas.Top"]};
    var element = visual.getParent();
    while (element) {
        result.left += element["Canvas.Left"];
        result.top += element["Canvas.Top"];
        element = element.GetParent();
    }
    return result;
} 

SLx.VisualTreeHelper.isVisual = function SLx$VisualTreeHelper$isVisual ( item ) 
{ 
    var type = item.toString(); 
    switch (type) 
    { 
        case "Canvas": 
        case "Ellipse": 
        case "Glyphs": 
        case "Image" : 
        case "Line" : 
        case "LineBreak" : 
        case "MediaElement" : 
        case "Path": 
        case "Polygon" : 
        case "Polyline": 
        case "Rectangle": 
        case "Run" :
        case "Shape" : 
        case "TextBlock" : 
        case "UIElement" : 
            return true ; 
        default: 
            return false;           
     }    
 } 
 
 
SLx.VisualTreeHelper.isContainer = function ( item ) 
{ 
    if ( item == null ) return false ; 
    
    return Object.getType(item).inheritsFrom  ( SLx.Panel ) ;    
} 

SLx.VisualTreeHelper.isControl = function SLx$VisualTreeHelper$isControl ( item ) 
{ 
    if (  ! SLx.VisualTreeHelper.isVisual  ( item )) 
    { 
        return Object.getType(item).inheritsFrom  ( SLx.Control ) || Object.getType(item).inheritsFrom ( SLx.Panel ); 
    } 
    return false; 

} 

SLx.VisualTreeHelper.alignVisual = function  ( visual, availwidth, availheight , horAlignment , vertAlignment) 
{ 

    if ( vertAlignment != SLx.VerticalAlignment.Top ) 
    { 
        var height = visual.height ; 
        
        if ( visual.toString () == "TextBlock"  ) 
            height = visual.actualheight ; 
                        
        if ( height < availheight ) 
        { 
            if ( vertAlignment == SLx.VerticalAlignment.Center ) 
            { 
                visual ["Canvas.Top"] =  ( availheight - height ) / 2 ; 
            } 
            else 
            { 
                visual ["Canvas.Top"] =  ( availheight - height ) ; 
            } 
        }
    } 
    
    if ( horAlignment != SLx.HorizontalAlignment.Left ) 
    { 
        var width = visual.Width ; 
        if ( visual.toString () == "TextBlock" ) 
            width = visual.actualWidth ; 
                        
        if ( width < availwidth ) 
        { 
            if ( horAlignment == SLx.HorizontalAlignment.Center ) 
            { 
                visual ["Canvas.Left"] =  ( availwidth - width ) / 2 ; 
            } 
            else 
            { 
                visual ["Canvas.Left"] =  ( availwidth - width ) ; 
            } 
        } 
    }        
}

SLx.VisualTreeHelper.getVisualFromItem = function ( item ) 
{ 
    var visual = null ; 
    var isControl = SLx.VisualTreeHelper.isControl ( item ) ; 
    if ( isControl ) 
    { 
        visual = item.get_visual ( ); 
    }
    else 
        visual = item ;  

        return visual ; 
}
  

SLx.EventArgs = function ( sender, args , more ) 
{ 
    this.sender = sender; 
    this.args = args; 
    
} 

  
    
    
SLx.LayoutManager = function ()
{ 
    this._controls = [] ; 
    this._roots = [] ; 
    this._invalidQueue = [] ; 
    this._doLayoutCallback = $delegate  (this, this._doLayout);          
} 

SLx.LayoutManager.prototype = 
{
    register : function  ( item ) 
    { 
        var alreadyRegistered = Array.contains ( this._controls , item ) ; 
        if ( !alreadyRegistered ) 
        { 
            Array.add ( this._controls, item ) ; 
            
            if ( item.get_logicalParent () == null ) 
            {             
                Array.add ( this._roots, item ); 
            } 
        } 
        
        return !alreadyRegistered ; 
    }, 
     
    
    
    invalidateAll  : function  (  ) 
    { 
        for ( var i = 0 ; i < this._roots.length ; i++ ) 
        { 
            var item = this._roots[i]; 
            this._invalidate ( item , true );                   
        } 
    }, 
    
    _invalidate  : function ( item ,force ) 
    {     
        this.invalidate( item );            
        if ( item.get_hasChildren () ) 
         {  
            for ( var i = 0 ; i < item.get_children().length ; i++ ) 
            { 
                this._invalidate ( item , force ); 
            } 
         } 
         else if ( item.get_hasContent () ) 
         { 
            this._invalidate ( item.get_content() , force ) ; 
         }            
    }, 
    
    
    invalidate : function ( sender ) 
    { 
       if ( Array.contains ( this._invalidQueue, sender )) 
       { 
            Array.remove ( this._invalidQueue, sender ); 
       } 
        
       if ( this._invalidQueue.length == 0 ||  this._invalidQueue.length > 3 ) 
            window.setTimeout ( this._doLayoutCallback , 0 );    
            
       Array.add ( this._invalidQueue, sender ); 
       
       
    } , 
    
    
    
    _doLayout : function  ( ) 
    { 
        //TODO: sync to prevent concurrent access? 
        
        var length = this._invalidQueue.length ; 
        
        for ( var i = 0 ; i < length ; i++ ) 
        { 
            var item = this._invalidQueue[0]; 
            while ( item.get_logicalParent () != null ) 
            { 
                Sys.Debug.assert ( item.get_logicalParent()._isMeasureInvalidated || SLx.Warning.ParentUpdatedChildLayout , "Not an error, but verify that parents w/ invalid children should is OK"); 
                if ( item.get_logicalParent().get_isLayoutDirty()  ) 
                { 
                    item = item.get_logicalParent();                
                }
                else break;                  
            } 
            
            Array.remove ( this._invalidQueue, item ); 
                       
            if ( item.get_isLayoutDirty () ) 
            { 
                Sys.Debug.trace ( "doLayout: " + item.toString ());  
                item.updateLayout(); 
            } 
            else 
                Sys.Debug.trace("doLayout: cached " + item.toString() ); 
        }    
        
        Sys.Debug.assert (  this._invalidQueue.length ==  0 || SLx.Warning.ExpectsNoScrollViewerForLayout ,  
        "It is OK for queue to not be empty, known scenario is scrollviewer" ) ; 
        
    } , 
    
    updateLogicalParent  : function ( child, newParent ) 
    { 
        //TODO : Is there more than updating root?         
        if ( Array.contains ( this._roots , child) ) 
            Array.remove ( this._roots, child ) ; 
            
        Sys.Debug.assert ( Array.contains ( this._controls, child )  || SLx.Warning.ChildRegisteredBeforeUpdate , "not an error, but expecting child should register before parent" ) ; 
        Sys.Debug.assert ( Array.contains ( this._controls, newParent) || SLx.Warning.ParentsRegistered , "not an error, but expecting parent registered" ) ; 
        
    } 
} 

 
        