/***			global objects			***/

var Browser = {
    IE:     !!(window.attachEvent && !window.opera),
    Opera:  !!window.opera,
    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
    MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
  }
  
// Enum object "FolderTypes" - the type of items the folder holds
var BranchTypes = {
	ALBUM : 0,
	TAG : 1,
	SHARED : 2,
	SOURCE : 3,
	NEW : 4
}

// the different types of an item. specially for the "Shared With" branch which holds all kind of types
var ItemTypes = {
	TIMELINE : 0,
	ALBUM : 1,
	ASSET : 2
}

// flags of permissions for actions on assets / containers
var PermissionFlags = {
	View : 1,
    Comment : 2,
    LimitedMarkPeople : 4,
    Tag : 8,
    Take : 16,
    MarkPeople : 32,
    ShareToView : 64,
    Distribute : 128,
    ChangeTexts : 256,
    ChangeDate : 512,
    DeleteComments : 1024,
    DeleteTags : 2048,
    Recall : 4096
}

var Consts = {
	PAGE_SIZE : 10,			// important: it is critical that (LOAD_AMOUNT > PAGE_SIZE) for the system to work
	LOAD_AMOUNT : 100,		// important: it is critical that (LOAD_AMOUNT > PAGE_SIZE) for the system to work
	LAST_ELEMENTS_AMOUNT : 30,
	PIXELS_PER_LETTER : 6,
	PIXELS_PER_BOLD_LETTER : 7,
	REBUILD_INTERVAL : 50,
	LOADING_IMAGE_DELAY : 200,
	ASSET_DETAILS_DELAY : 800,
	ACTION_RETRIES : 2
}

// the structure of the this object properties:
// [typeID] : {
//		UseThumb : [true/false], 
//		IconURL : [some url], 
//		Description : [some description]
//	}
var AoMTypes = {
	numOfLoadingTries : 0,
	isLoaded : false,
	
	load : function()
	{
	  if (this.isLoaded) return;
		executeWebRequest("AoMTypes.GetAoMTypes",[{name:"SerType", value:2}],{onSuccessFunction:parseAoMTypesOnSuccess, onFailureFunction:parseAoMTypesOnFailure});
	}
}

var TargetTypes = {
	PUBLIC : 1,
	NETWORK : 2,
	GROUP : 3,
	CONTACT : 4,
	VIEWER : 5
}

// the structure of the this object properties:
var NewsFeed = {
	numOfLoadingTries : 0,
	isLoaded: false,

	load : function()
	{
        executeWebRequest("Timelines.GetInboxEntities",[],{onSuccessFunction:parseNewsFeedOnSuccess, onFailureFunction:parseNewsFeedOnFailure}, undefined, callbackXml);
    }
}
function getNewsPageHtml(pageNumber) {

    // temp puse waiting for loading compleate of the NewsFedd
    /*
    //while (!NewsFeed.isLoaded) {
    if (!NewsFeed.isLoaded) {
        console.info('waiting')
        var date = new Date();
        var curDate = null;
        do {curDate = new Date();}
        while(curDate-date < 500);
    }
    */

    var newsContainerHtml = "";

    var firstObj = (pageNumber*10)-10;
    var lastObj = (pageNumber*10);
    if (lastObj > NewsFeed.length) {lastObj = NewsFeed.length};

    for (var i = firstObj; i < lastObj; i++) {

        console.info(i)
        console.info(NewsFeed[i])

        if (NewsFeed[i].AomType != null) {
            iconURL = AoMTypes[parseInt(NewsFeed[i].AomType)].SidebarIconURL;
        } else {
            iconURL = "";
        }

        newsContainerHtml +=
		    '<div id="ContainerRow' + NewsFeed[i].ID + '" name="ContainerRow" title="' + NewsFeed[i].Title + '" class="Container" \
				    containerCacheID="' + NewsFeed[i].ID + '" selectedAssets="none" > \
			    <div class="Container" style="float:left;" onclick="toggleContainer(\'' + NewsFeed[i].ID + '\',false);">\
				    <div class="Expander"><div class="Icon ContainerExpanderOpenImage" id="ContainerExpanderImage' + NewsFeed[i].ID + '"></div></div> \
				    <div class="Image"><img src="' + iconURL + '" alt="" class="Icon"/></div> \
				    <div id="ContainerTitle' + NewsFeed[i].ID + '" class="Title" name="containerTitle" title="' + NewsFeed[i].Title + '" >' + NewsFeed[i].Title + '</div> \
				    <div class="ChildrenNum" id="ContainerChildrenNum' + NewsFeed[i].ID + '">(' + NewsFeed[i].children.length + ')</div> \
			    </div>\
			    <!--<div id="HiddenActions' + NewsFeed[i].ID + '" class="HiddenActions" onclick="toggleContainer(\'' + NewsFeed[i].ID + '\',false);"></div>\
			    <div id="actions' + NewsFeed[i].ID + '" class="Actions" onclick="showActionsMenu(\'' + NewsFeed[i].ID + '\',event);">\
				    <div class="ActionsText">Actions</div>\
				    <div class="ActionsImage"><div id="ActionsExpanderImage' + NewsFeed[i].ID + '" class="Icon ActionsExpanderImage"></div></div>\
			    </div>-->\
		    </div>\
		    <div id="ContainerWindow' + NewsFeed[i].ID + '" class="ContainerWindow" style="display:none;">\
		    '

		        // Build the childerns content HTML
		        for (var j = 0; j < NewsFeed[i].children.length ; j++) {
                    titleText = Browser.IE ? this.AssetObject.Title : Resize.cutoffText(NewsFeed[i].children[j].Title, false, Resize.AssetWidth);

                    newsContainerHtml +=
		                    '<div id="AssetRow' + NewsFeed[i].children[j].ID + '" class="Asset" > \
			                    <div class="Input">&nbsp;</div> \
			                    <div class="Details" onclick="ShowAssetOnTimeline(' + NewsFeed[i].children[j].ID + ');">\
				                    <div class="Image"><img src="' + NewsFeed[i].children[j].Url + '" alt="" class="Icon" onload="!this.src.match(\'' + NewsFeed[i].children[j].Url + '\')?this.src=\'' + NewsFeed[i].children[j].Url + '\':null" /></div> \
				                    <div id="AssetTitle' + NewsFeed[i].children[j].ID + '" class="Name" name="assetTitle" assetname="' + NewsFeed[i].children[j].Title + '" style="width:' + Resize.AssetWidth + 'px;">' + titleText + '</div> \
			                    </div>\
			                    <div class="Type">&nbsp;</div> \
		                    </div>';
        		
        		    
		        }
		        // test end

		        newsContainerHtml += '</div>';
    }

    return newsContainerHtml;
}
function getNewsPagerHtml() {
    // build the pager
    if (this.Children.length > Consts.PAGE_SIZE) {
        var isFirstPage = (pageNumber == 1);
        var isLastPage = (lastIndex == this.Children.length);
        var fromContainer = (pageNumber - 1) * Consts.PAGE_SIZE + 1;
        var toContainer = fromContainer + containers.length - 1;
        var changeToPreviousString = 'changeBranchPage(\'' + this.CacheID + '\',' + (pageNumber - 1) + ');';
        var changeToNextString = 'changeBranchPage(\'' + this.CacheID + '\',' + (pageNumber + 1) + ');';

        containersHtml += ' \
		    <div class="Pager"><table align="center"><tr><td> \
			    <div class="LinkImage"><div class="Icon ' + (isFirstPage ? ('PagerPrevDimmImage') : ('PagerPrevImage" onclick="' + changeToPreviousString)) + '"></div></div>\
			    <div class="Link"><a ' + (isFirstPage ? ('class="disabled" href="#') : (' href="javascript:' + changeToPreviousString)) + '">Prev</a></div>\
			    <div class="PageNumbers">' + fromContainer + ' - ' + toContainer + ' of ' + this.NumOfChildren + '</div> \
			    <div class="Link"><a ' + (isLastPage ? ('class="disabled" href="#') : (' href="javascript:' + changeToNextString)) + '">Next</a></div>\
			    <div class="LinkImage"><div class="Icon ' + (isLastPage ? ('PagerNextDimmImage') : ('PagerNextImage" onclick="' + changeToNextString)) + '"></div></div> \
		    </td></tr></table></div>';
    }
}



// the structure of the this object properties:
// [targetID] : {
//		Name : [target name],
//		TargetTypeID : [type of target], 
//		SmallAvatarURL : [some url], 
//		AvatarURL : [some url]
//	}
var ContactCloud = {
  numOfLoadingTries: 0,
  isLoaded: false,
  err: false,

  load: function() {
    if (this.isLoaded) return;
    if (!flashvars.IsLoggedIn) {
      this.isLoaded = true;
      this.err = true;
    }
    //parseContactCloudXML(flash.getContactCloud());
    executeWebRequest("Contacts.GetContactCloud", [{ name: "SerType", value: 2}], { onSuccessFunction: parseContactCloudOnSuccess, onFailureFunction: parseContactCloudOnFailure });
  }
}

// object to handle the resizing of the sidebar.
var Resize = {
	Containers : [],	// to hold all container elements that will be resized on resizing the sidebar
	Assets : [],		// to hold all asset elements that will be resized on resizing the sidebar
	ElementsValid : false,	// a flag to mark if need to update the elements array.
	ContainerWidth : 0,
	AssetWidth : 0,
	
	// set the width of elements
	updateWidth : function()
	{
	
		var sidebarWidth = $get("RootTreeViewDiv").offsetWidth;
		
		this.ContainerWidth = sidebarWidth - 170;
		if (this.ContainerWidth < 100)
			this.ContainerWidth = 100;
			
		this.AssetWidth = sidebarWidth - 130;
		if (this.AssetWidth < 140)
			this.AssetWidth = 140;
	},
	
	// return list of the asset / container title elements
	updateResizableElements : function()
	{
		var allDivElements = document.getElementsByTagName('div');
		this.Containers = [];
		this.Assets = [];
		
		for (var i = 0; i < allDivElements.length; i++)
		{
			if (allDivElements[i].getAttribute('name') == 'assetTitle')
				this.Assets[this.Assets.length] = allDivElements[i];
			else if (allDivElements[i].getAttribute('name') == 'containerTitle')
				this.Containers[this.Containers.length] = allDivElements[i]; 
		}
	},
	
	// resize the data in tree - the "..." in asset names
	resizeTreeData : function()
	{
		this.updateWidth();
		var originalTitle;
		
		// check if need to update resizable elements array
		if (!Resize.ElementsValid)
		{
			this.updateResizableElements();
			Resize.ElementsValid = true;
		}
			
		// update the width of all container title elements
		for (var i = 0, j = Resize.Containers.length; i < j; i++)
		{		
			Resize.Containers[i].style.width = "";
					
			// IE has the css "text-overflow:ellipsis" that automaticly cuts the text and adds "..."
			if (!Browser.IE)
			{
				originalTitle = Resize.Containers[i].getAttribute('title');
				Resize.Containers[i].innerHTML = this.cutoffText(originalTitle, true, this.ContainerWidth);
			}
			
			if (Resize.Containers[i].offsetWidth > this.ContainerWidth)
			{
				Resize.Containers[i].style.width = this.ContainerWidth + "px";
			}
		}
		
		// update the width of all asset title elements
		for (var i = 0, j = Resize.Assets.length; i < j; i++)
		{
			Resize.Assets[i].style.width = this.AssetWidth + "px";
			
			// IE has the css "text-overflow:ellipsis" that automaticly cuts the text and adds "..."
			if (!Browser.IE)
			{
				originalTitle = Resize.Assets[i].getAttribute('assetname');
				Resize.Assets[i].innerHTML = this.cutoffText(originalTitle, false, this.AssetWidth);
			}
				
		}
	},
	
	// gets text and width in pixels and returns a text that fits in the width with "..."
	cutoffText : function(text, bold, width)
	{
		var letterWidth = bold ? Consts.PIXELS_PER_BOLD_LETTER : Consts.PIXELS_PER_LETTER;
		var numOfLettersFit = Math.floor(width / letterWidth) - 1;
		if (text.length > numOfLettersFit)
			text = text.substring(0, numOfLettersFit) + "...";
		return text;
	}
}

// holds the current executing action. 
// this is for locking the sidebar while an action is in process.
var pendingAction = {
	pending : false,
	numOfRetries : 0,
	functionName : "",
	functionParams : "",
	callbackData : ""
}

/** cached data		**/

// overview - the cacheBranches array holds the containers that hold the assets in a hierarchic structure.
// the children of the containers are object with the cacheID of asset in the container and a reference to an asset object
// in order to hold each asset object only once in memory even thought it appears in more than one container in the sidebar
var cacheBranches = [];				// the whole cache

// holds references for all the cache object for fast accessing and searching
// the structure of the this object properties:
// [cacheID] : cache object (Branch / Container / CacheAsset / News Feed)
var cacheDictionary = {};		

// holds all the assets in one place so that they exist only once in memory.
// important: access to the assets is done only through the "cacheBranches" or "cacheDictionary" for fast access,
// the only time access is done directly from here is when inserting new assets to cache
// the structure of the this object properties:
// [assetID] : Asset object
var assets = {};

/**		end of cached data		**/


// data about the current viewer (user). recieved from server with the contact cloud.
// structure - 
//		ID : <id of current user>
//		DefaultSharing : <default sharing level>
var viewer = {
	numOfLoadingTries : 0,
	
	loadDefaultSharing : function()		// loading user's default sharing level
	{
		executeWebRequest("Sidebar.GetDefaultSharingLevel",[{name:"SerType", value:2}],{onSuccessFunction:parseDefaultSharingOnSuccess, onFailureFunction:parseDefaultSharingOnFailure});	
	}
}

var mouseOverContext = false;	// a flag to mark whether the mouse is over a context menu
var openPopupWindows = [];		// will hold the IDs of the current open popupwindows

// will hold all the returned IDs from the setTimeout functions in order to cancel them when needed.
// every entry will hold the cacheid of the window being loaded and the timerID for the function building that window
var BuildWindowTimers = {};
var LoadingTimers = {};		// holds the timer IDs of the setTimeout for the loading image which is also displayed with a timer
var AssetDetailsTimerID;
var ControlsNamespace = [
  "Sidebar",
  "AssetPage"];

/***		end of global objects		***/


/***		 the Asset object			***/

// ctor
function Asset(id, title, defaultIconURL, iconURL, created, type, description, permission, creator, tagCreator, width, height, aomTypeId)
{
	// properties of the asset
	this.ID = id;
	this.Title = title;
	this.DefaultIconURL = defaultIconURL;
	this.IconURL = iconURL;
	this.Created = created;
	this.Type = type;
	this.Description = description;
	this.Permission = permission;
	this.Creator = creator;				// only for the tag assets
	this.TagCreator = tagCreator;		// only for the tag assets
	
    this.Width = width;
    this.Height = height;
    this.aomTypeId = aomTypeId;
	
	this.ContainerCacheIDs = [];	// holds the cacheIDs of the containers which the asset is in
	this.AssetCacheIDs = [];		// holds the cacheIDs of the "CacheAssets" in the different containers
}

// change the asset's properties
Asset.prototype.update = function(id, title, defaultIconURL, iconURL, created, type, description, permission, creator, tagCreator, width, height, aomTypeId)
{
	// properties of the asset
	this.ID = id;
	this.Title = title;
	this.DefaultIconURL = defaultIconURL;
	this.IconURL = iconURL;
	this.Created = created;
	this.Type = type;
	this.Description = description;
	this.Permission = permission;
	this.Creator = creator;				// only for the tag assets
	this.TagCreator = tagCreator		// only for the tag assets

    this.Width = width;
    this.Height = height;
    this.aomTypeId = aomTypeId;
}

// instance method to change the asset name in cache and GUI
Asset.prototype.rename = function(newName)
{
	var titleElement
	this.Title = newName;
	var titleText = Browser.IE ? this.Title : Resize.cutoffText(this.Title, true, Resize.AssetWidth);
	
	// go over the list of the "AssetCacheIDs" and change all the specific cache assets in cache and GUI
	for (var i = 0, j = this.AssetCacheIDs.length; i < j; i++)
	{
		titleElement = $get('AssetTitle' + this.AssetCacheIDs[i]);
		if (titleElement)
		{
			titleElement.innerHTML = titleText;
			titleElement.setAttribute("assetname", this.Title);
		}
	}
}

// deletes the asset from cache and GUI
Asset.prototype.deleteAsset = function()
{
	var container, assetIndex;
	
	// delete the cacheAssets in the different containers with this asset and
	// refresh all GUI containers that contain the asset
	for (var i = 0, j = this.ContainerCacheIDs.length; i < j; i++)
	{
		container = cacheDictionary[this.ContainerCacheIDs[i]];
		assetIndex = container.indexOfAsset(this.AssetCacheIDs[i]);
		container.Children.splice(assetIndex, 1);
		if (container.NumOfChildren > 0)
			container.NumOfChildren--;
		
		buildContainerWindow(this.ContainerCacheIDs[i], 1);
		
		delete cacheDictionary[this.AssetCacheIDs[i]];
	}
	
	// delete this asset from the "assets" object	
	delete assets[this.ID];
}

/***		end of Asset object			***/

/***		CacheAsset object			***/

// this is the object for a specific asset in a container

function CacheAsset(cacheID, asset)
{
	this.CacheID = cacheID;		// a unique id for every object in the cache. a string: [branchID][containerID][assetID]
	this.AssetObject = asset;
}

// returns the html for the asset row
CacheAsset.prototype.getHtml = function(containerCacheID)
{
	titleText = Browser.IE ? this.AssetObject.Title : Resize.cutoffText(this.AssetObject.Title, false, Resize.AssetWidth);
	
	var assetHtml = 
		'<div id="AssetRow' + this.CacheID + '" class="Asset" > \
			<div class="Input"><input assetID="' + this.AssetObject.ID + '" assetCacheID="' + this.CacheID + '" name="Asset' + containerCacheID + '" creator="' + this.AssetObject.Creator + '" tagCreator="' + this.AssetObject.TagCreator + '" \
				onclick="assetSelectionChanged(this,\'' + containerCacheID + '\',\'' + this.CacheID + '\');" type="checkbox" /></div> \
			<div class="Details" onclick="ShowAssetOnTimeline(' + this.AssetObject.ID + ');">\
				<div class="Image"><img src="' + this.AssetObject.DefaultIconURL + '" alt="" class="Icon" onload="!this.src.match(\'' + this.AssetObject.IconURL + '\')?this.src=\'' + this.AssetObject.IconURL + '\':null" /></div> \
				<div id="AssetTitle' + this.CacheID + '" class="Name" name="assetTitle" assetname="' + this.AssetObject.Title + '" style="width:' + Resize.AssetWidth + 'px;">' + titleText + '</div> \
			</div>\
			<div class="Type">' + this.AssetObject.Description + '</div> \
		</div>';

	return assetHtml;
}

/***		end of CacheAsset object			***/


/***		the Container object		***/

// ctor
// optional arguments: created
function Container(id, title, children, iconURL, created, albumWhen, permission, cacheID, branchType, branch)
{
	// properties of the container
	this.ID = id;
	this.Title = title;
	this.NumOfChildren = children;
	this.IconURL = iconURL;
	this.Created = created;
	this.AlbumWhen = albumWhen;
	this.Permission = permission;
	
	// properties of the cache object
	this.CacheID = cacheID;			// a unique id for every object in the cache. a string: [branchID][containerID]
	this.BranchType = branchType; 	// Enum object "BranchTypes" - the type of items the container holds
	this.Branch = branch;
	
	this.Children = [];				// object array that will hold the "CacheAsset" objects of the Container.
	this.IsLoading = false;			// a flag for knowing if the container is in the middle of getting data from the server
	this.LoadingRetries = 0;		// to keep the reloading times in case of error in loading
	this.IsFull = false;			// a flag for knowing if the container has loaded from the server all the assets
}

// change the container's properties
Container.prototype.update = function(id, title, children, iconURL, created, albumWhen, permission, cacheID, branchType, branch) 
{
    // properties of the container
    this.ID = id;
    this.Title = title;
    this.NumOfChildren = children;
    this.IconURL = iconURL;
    this.Created = created;
    this.Permission = permission;
    this.AlbumWhen = albumWhen;

    // properties of the cache object
    this.CacheID = cacheID; 		// a unique id for every object in the cache. a string: [branchID][containerID]
    this.BranchType = branchType; 	// Enum object "BranchTypes" - the type of items the container holds
    this.Branch = branch;

    this.Children = []; 			// the array that will hold the "CacheAsset" objects of the Container
    this.IsLoading = false; 		// a flag for knowing if the container is in the middle of getting data from the server
    this.LoadingRetries = 0; 	// to keep the reloading times in case of error in loading
    this.IsFull = false; 		// a flag for knowing if the container has loaded from the server all the assets	
}

// loads the content from server to the Children array of the Container
// the function fetches a certain amount of data each time and adds it to the array.
Container.prototype.prefetchData = function() {

    var from, amount; 	// for the "skip" and "take" parameters

    from = this.Children.length;
    amount = Consts.LOAD_AMOUNT;

    this.IsLoading = true;

    // execute the web request with the correct method by the type of container
    switch (this.BranchType) {
        case BranchTypes.NEW: 
            {
                executeWebRequest("Timelines.GetInboxEntities", [], { onSuccessFunction: parseNewsFeedOnSuccess, onFailureFunction: parseNewsFeedOnFailure }, undefined, callbackXml);
                break;
            }
        case BranchTypes.ALBUM: 
            {
                executeWebRequest("Sidebar.GetAlbumAssets", [{ name: "SerType", value: 2 }, { name: "AlbumID", value: this.ID }, { name: "Skip", value: from }, { name: "Take", value: amount}], { onSuccessFunction: parseContainerAssetsOnSuccess, onFailureFunction: parseContainerAssetsOnFailure, branch: this.Branch, container: this });
                break;
            }
        case BranchTypes.TAG: 
            {
                executeWebRequest("Sidebar.GetTagAssets", [{ name: "SerType", value: 2 }, { name: "TagID", value: this.ID }, { name: "Skip", value: from }, { name: "Take", value: amount}], { onSuccessFunction: parseContainerAssetsOnSuccess, onFailureFunction: parseContainerAssetsOnFailure, branch: this.Branch, container: this });
                break;
            }
        case BranchTypes.SHARED: 
            {
                executeWebRequest("Sidebar.GetSubjects", [{ name: "SerType", value: 2 }, { name: "TargetID", value: this.ID }, { name: "Skip", value: from }, { name: "Take", value: amount}], { onSuccessFunction: parseContainerAssetsOnSuccess, onFailureFunction: parseContainerAssetsOnFailure, branch: this.Branch, container: this });
                break;
            }
        case BranchTypes.SOURCE: 
            {
                executeWebRequest("Sidebar.GetChannelAssets", [{ name: "SerType", value: 2 }, { name: "ChannelID", value: this.ID }, { name: "Skip", value: from }, { name: "Take", value: amount}], { onSuccessFunction: parseContainerAssetsOnSuccess, onFailureFunction: parseContainerAssetsOnFailure, branch: this.Branch, container: this });
                break;
            }
    }
}

// returns the html for the container row
Container.prototype.getHtml = function(branchID) {

    var titleText = Browser.IE ? this.Title : Resize.cutoffText(this.Title, true, Resize.ContainerWidth);

    var containerHtml =
		'<div id="ContainerRow' + this.CacheID + '" name="ContainerRow" title="' + this.Title + '" class="Container" \
				containerCacheID="' + this.CacheID + '" selectedAssets="none" > \
			<div class="Container" style="float:left;">\
				<div class="Expander" onclick="toggleContainer(\'' + this.CacheID + '\');"><div class="Icon ContainerExpanderOpenImage" id="ContainerExpanderImage' + this.CacheID + '"></div></div> \
				<div class="Image"><img src="' + this.IconURL + '" alt="" class="Icon"/></div> \
				<div id="ContainerTitle' + this.CacheID + '" class="Title" name="containerTitle" title="' + this.Title + '" onclick="goToAlbum(\'' + this.ID + '\')">' + titleText + '</div> \
				<div class="ChildrenNum" id="ContainerChildrenNum' + this.CacheID + '">(' + this.NumOfChildren + ')</div> \
			</div>\
			<div id="HiddenActions' + this.CacheID + '" class="HiddenActions" onclick="toggleContainer(\'' + this.CacheID + '\');"></div>\
			<div id="actions' + this.CacheID + '" class="Actions" onclick="showActionsMenu(\'' + this.CacheID + '\',event);">\
				<div class="ActionsText">Actions</div>\
				<div class="ActionsImage"><div id="ActionsExpanderImage' + this.CacheID + '" class="Icon ActionsExpanderImage"></div></div>\
			</div>\
		</div><div id="ContainerWindow' + this.CacheID + '" class="ContainerWindow" style="display:none;"></div>';

    return containerHtml;
}

// returns html for a page of Container assets. the count of pages starts from 1.
// checks if the page requested is close to end of cached data and if so, 
// prefetches more assets from server to cache.
Container.prototype.getWindowPageHtml = function(pageNumber)
{
	var firstIndex = Consts.PAGE_SIZE * (pageNumber - 1);
	var lastIndex = firstIndex + Consts.PAGE_SIZE;	
	var assetsHtml = "";
	
	// check if requested data is in the cache - build the page
	if (this.Children.length >= lastIndex)
	{
		// OK, keep the default setting
	}
	// if the PAGE_SIZE elements aren't available but cache is full - build with the data that exists
	else if (this.IsFull)		
	{
		// if finished loading all assets from server and no available data
		if (this.Children.length <= firstIndex)
		{
			return '<table align="center"><tr><td>No data available</td></tr></table>';
		}
		else		// part of the data is available
		{
			lastIndex = this.Children.length;
		}
	}
	// data isn't available, and cache isn't full yet,
	// if the container isn't in middle of loading - prefetch data from server
	else if (!this.IsLoading)	
	{
		if (this.LoadingRetries <= Consts.ACTION_RETRIES)
		{
			this.prefetchData();
			return "";
		}
		else		// error in fetching data from server
		{
			return '<table align="center"><tr><td>Error in fetching data from server</td></tr></table>';
		}
	}
	else	// loading...
	{
		return "";
	}

	// check if we're close to end of cache and need to load more from server to cache
	if ((!this.IsFull) && (this.Children.length - lastIndex < Consts.LAST_ELEMENTS_AMOUNT))
		this.prefetchData();	
		
	var selectAllText;		// the text will be according to the type of branch / container
	switch (this.BranchType) {
		case BranchTypes.NEW:{
			break;
		}
		case BranchTypes.ALBUM:{
			selectAllText = "Album";
			break;
		}
		case BranchTypes.TAG:{
			selectAllText = "Tag";
			break;
		}
		case BranchTypes.SHARED:{
			selectAllText = "Group";
			break;
		}		
	}
	
	// in the source branch show "setting" instead of the selection buttons
	if (this.BranchType == BranchTypes.SOURCE)
	{
		assetsHtml = ' \
			<div class="SelectionButtons"> \
				<a href="javascript:setSourceSettings(' + this.ID + ');" class="SelectionButton">settings</a> \
			<div class="SelectionText" id="SelectionText' + this.CacheID + '">No Assets Selected</div>';

	}
	else
	{
		assetsHtml = ' \
			<div class="SelectionButtons"><strong>Select:</strong> \
				<a id="SelectAll' + this.CacheID + '" href="Javascript: void(0)" onclick="javascript:selectAllContainer(\'' + this.CacheID + '\');" \
				onfocus="Javascript: blur(this)" class="SelectionButton">' + selectAllText + '</a> \
				<a id="UnSelectAll' + this.CacheID + '" href="Javascript: void(0)" onclick="javascript:unSelectAllContainer(\'' + this.CacheID + '\');" \
				onfocus="Javascript: blur(this)" class="SelectionButtonDisabled">None</a></div> \
			<div class="SelectionText" id="SelectionTextDiv' + this.CacheID + '"><div class="Text"  id="SelectionText' + this.CacheID + '">No ' + (this.BranchType == BranchTypes.SHARED ? "Items" : "Assets") + ' Selected</div></div>';
	}
		
	// build the window page html
	var cacheAssets = this.Children.slice(firstIndex, lastIndex);
		
	// the assets rows
	for (var i = 0, j = cacheAssets.length; i < j; i++)
	{
		assetsHtml += cacheAssets[i].getHtml(this.CacheID);
	}	
	
	// build the pager
	if (this.Children.length > Consts.PAGE_SIZE) 
	{
		var isFirstPage = (pageNumber == 1);
		var isLastPage = (lastIndex == this.Children.length);
		var fromAsset = (pageNumber - 1) * Consts.PAGE_SIZE + 1;
		var toAsset = fromAsset + cacheAssets.length - 1;
		var changeToPreviousString = 'changeContainerPage(\'' + this.CacheID + '\',' + (pageNumber-1) + ');';
		var changeToNextString = 'changeContainerPage(\'' + this.CacheID + '\',' + (pageNumber+1) + ');';
		
		assetsHtml += ' \
		<div class="Pager"><table align="center"><tr><td> \
			<div class="LinkImage"><div class="Icon ' + (isFirstPage ? ('PagerPrevDimmImage') : ('PagerPrevImage" onclick="' + changeToPreviousString)) + '"></div></div>\
			<div class="Link"><a ' + (isFirstPage ? ('class="disabled" href="#') : (' href="javascript:' + changeToPreviousString)) + '">Prev</a></div>\
			<div class="PageNumbers">' + fromAsset + ' - ' + toAsset + ' of ' + this.NumOfChildren + '</div> \
			<div class="Link"><a ' + (isLastPage ? ('class="disabled" href="#') : (' href="javascript:' + changeToNextString)) + '">Next</a></div>\
			<div class="LinkImage"><div class="Icon ' + (isLastPage ? ('PagerNextDimmImage') : ('PagerNextImage" onclick="' + changeToNextString)) + '"></div></div> \
		</td></tr></table></div>';
	}
	
	return assetsHtml;
}

// checks if an asset object reference exists in the container
Container.prototype.indexOfAsset = function(cacheID)
{
	for (var i = 0, j = this.Children.length; i < j; i++)
	{
		if (this.Children[i].CacheID == cacheID)
			return i;
	}
	
	return -1;
}

// clear the "Children" array of container and their objects in the "cacheDictionary"
Container.prototype.clearChildren = function()
{
	// first delete all the "CacheAsset" objects in the cacheDictionary
	for (var i = 0, j = this.Children.length; i < j; i++)
	{
		delete cacheDictionary[this.Children[i].CacheID];
	}
	
	this.Children = [];
	this.IsFull = false;
}

// rename a container (only album containers are allowed to be renamed)
Container.prototype.rename = function(newName)
{
	this.Title = newName;
	var titleText = Browser.IE ? this.Title : Resize.cutoffText(this.Title, true, Resize.ContainerWidth);
	var titleElement = $get('ContainerTitle' + this.CacheID);
	titleElement.innerHTML = titleText;
}

// deleteing a container (only Album) moves all the assets in it to the "assets not in album" container and then delete the container itself
Container.prototype.deleteContainer = function()
{
	// all the assets in the album will move to the "Assets not in Album" container so delete it's cache
	var assetsNotInAlbum = this.Branch.Children[0];
	assetsNotInAlbum.clearChildren();
	
	// delete the album from the "Albums" branch children array and refresh the "Albums" branch GUI
	var containerIndex = this.Branch.indexOfContainer(this.CacheID);
	this.Branch.Children.splice(containerIndex, 1);
	if (this.Branch.NumOfChildren > 0)
		this.Branch.NumOfChildren--;
	
	buildBranchWindow(this.Branch.CacheID, 1);

	// delete this asset from the "cacheDictionary" and "assets" object
	delete cacheDictionary[this.CacheID];
}

// add selected assets to container
Container.prototype.addAssets = function(selectedIDs)
{
	// as for now - just delete the "Children" array of the container 
	// to get the updated children when opening again	
	this.clearChildren();
	
	this.NumOfChildren += selectedIDs.length;
	
	// update GUI
	var containerWindow = $get('ContainerWindow' + this.CacheID);
	
	// check if container is in GUI at all
	if (containerWindow)
	{
		if (containerWindow.style.display == 'block')	// if the added to container is open - rebuild it to refresh
		{
			// show the loading image until assets are built
			LoadingTimers[this.CacheID] = setTimeout(function(){ShowLoadingImage(containerWindow, this.CacheID)}, Consts.LOADING_IMAGE_DELAY);

			buildContainerWindow(this.CacheID, 1);
		}
		else		// if container window is closed - just change the number of children to see the change
		{
			var numOfChildrenElement = $get("ContainerChildrenNum" + this.CacheID);
			numOfChildrenElement.innerHTML = "(" + this.NumOfChildren + ")";
		}
	}	
}

// remove selected assets from the container
Container.prototype.removeAssets = function(selectedIDs)
{
	var asset;
	
	// for each of the selected assets - 	
	for (var i = 0, j = selectedIDs.length; i < j; i++)
	{
		// remove it from the "AssetCacheIDs" and "ContainerCacheIDs" lists in the Asset object,
		asset = cacheDictionary[selectedIDs[i]].AssetObject;
		for (var x = 0, z = asset.AssetCacheIDs.length; x < z; x++)
		{
			if (asset.AssetCacheIDs[x] == selectedIDs[i])
			{
				asset.AssetCacheIDs.splice(x, 1);
				break;
			}
		}
		for (var x = 0, z = asset.ContainerCacheIDs.length; x < z; x++)
		{
			if (asset.ContainerCacheIDs[x] == this.CacheID)
			{
				asset.ContainerCacheIDs.splice(x, 1);
				break;
			}
		}
		
		// remove it from the cacheDictionary,
		delete cacheDictionary[selectedIDs[i]];
		
		// remove it from its container "Children" array	
		this.Children.splice(this.indexOfAsset(selectedIDs[i]), 1);		
	}
	
	this.NumOfChildren -= selectedIDs.length;
	buildContainerWindow(this.CacheID, 1);
}

/***		end of Container object		***/


/***		the Branch object		***/

// ctor
// optional arguments: created
function Branch(id, title, children, imageClass, cacheID, branchType)
{
	// properties of the branch
	this.ID = id;
	this.Title = title;
	this.NumOfChildren = children;
	this.ImageClass = imageClass;
	// properties of the cache object
	this.CacheID = cacheID;			// a unique id for every object in the cache. a string: [branchID][containerID]
	this.BranchType = branchType; 	// Enum object "BranchTypes" - the type of items the container holds
	this.Children = [];				// the array that will hold the "Container" objects of the branch
	this.IsLoading = false;			// a flag for knowing if the branch is in the middle of getting data from the server
	this.LoadingRetries = 0;		// to keep the reloading times in case of error in loading
	this.LoadingError = false;
	this.IsFull = false;			// a flag for knowing if the branch has loaded from the server all the assets
	
}

// checks if an container object reference exists in the branch
Branch.prototype.indexOfContainer = function(cacheID)
{
	for (var i = 0, j = this.Children.length; i < j; i++)
	{
		if (this.Children[i].CacheID == cacheID)
			return i;
	}
	
	return -1;
}

// loads the content from server to the Children array of the Container
// the function fetches a certain amount of data each time and adds it to the array.
Branch.prototype.prefetchData = function() {

    var from, amount; 	// for the "skip" and "take" parameters

    from = this.Children.length;
    amount = Consts.LOAD_AMOUNT;

    this.IsLoading = true;

    // execute the web request with the correct method by the type of branch
    switch (this.BranchType) {
        case BranchTypes.NEW:
            {
                executeWebRequest("Timelines.GetInboxEntities", [], { onSuccessFunction: parseNewsFeedOnSuccess, onFailureFunction: parseNewsFeedOnFailure }, undefined, callbackXml);
                break;
            }
        case BranchTypes.ALBUM:
            {
                executeWebRequest("Sidebar.GetAlbums", [{ name: "SerType", value: 2 }, { name: "Skip", value: from }, { name: "Take", value: amount}], { onSuccessFunction: parseBranchContainersOnSuccess, onFailureFunction: parseBranchContainersOnFailure, branch: this });
                break;
            }
        case BranchTypes.TAG:
            {
                executeWebRequest("Sidebar.GetTags", [{ name: "SerType", value: 2 }, { name: "Skip", value: from }, { name: "Take", value: amount}], { onSuccessFunction: parseBranchContainersOnSuccess, onFailureFunction: parseBranchContainersOnFailure, branch: this });
                break;
            }
        case BranchTypes.SHARED:
            {
                executeWebRequest("Sidebar.GetTargets", [{ name: "SerType", value: 2 }, { name: "Skip", value: from }, { name: "Take", value: amount}], { onSuccessFunction: parseBranchContainersOnSuccess, onFailureFunction: parseBranchContainersOnFailure, branch: this });
                break;
            }
        case BranchTypes.SOURCE:
            {
                executeWebRequest("Sidebar.GetChannels", [{ name: "SerType", value: 2 }, { name: "Skip", value: from }, { name: "Take", value: amount}], { onSuccessFunction: parseBranchContainersOnSuccess, onFailureFunction: parseBranchContainersOnFailure, branch: this });
                break;
            }
    }
}

// returns the html of the branch row
Branch.prototype.getHtml = function()
{	
	var branchHtml =	
		'<div id="BranchRow' + this.CacheID + '" branchCacheID="' + this.CacheID + '" class="Branch" name="Branch" onclick="toggleBranch(this,\'' + this.CacheID + '\');"> \
			<div class="Expander"><div class="Icon BranchExpanderOpenImage" id="BranchExpanderImage' + this.CacheID + '" ></div></div> \
			<div class="Image"><div class="Icon ' + this.ImageClass + '"></div></div> \
			<div class="Title">' + this.Title + '</div> \
			<!--<div class="ChildrenNum" id="BranchChildrenNum' + this.CacheID + '">(' + this.NumOfChildren + ')</div>--> \
			<div class="ChildrenNum" id="BranchChildrenNum' + this.CacheID + '">(-)</div> \
		</div><div id="BranchWindow' + this.CacheID + '" class="BranchWindow" style="display:none;"></div>';
	
	return branchHtml;
}

// returns html for a page of Branch containers. the count of pages starts from 1.
// checks if the page requested is close to end of cached data and if so, 
// prefetches more containers from server to cache.
Branch.prototype.getWindowPageHtml = function(pageNumber) {

    var firstIndex = Consts.PAGE_SIZE * (pageNumber - 1);
    var lastIndex = firstIndex + Consts.PAGE_SIZE;
    var containers = [];
    var containersHtml = "";

    // check if requested data is in the cache - build the page
    if (this.Children.length >= lastIndex) {
        // OK, keep the default setting
    }
    // if the PAGE_SIZE elements aren't available but cache is full - build with the data that exists
    else if (this.IsFull) {
        // if finished loading all assets from server and no available data
        if (this.Children.length <= firstIndex) {
            return '<table align="center"><tr><td>No data available</td></tr></table>';
        }
        else		// part of the data is available
        {
            lastIndex = this.Children.length;
        }
    }
    // data isn't available, and cache isn't full yet,
    // if the container isn't in middle of loading - prefetch data from server
    else if (!this.IsLoading) {
        if (this.LoadingRetries <= Consts.ACTION_RETRIES) {
            this.prefetchData();
            return "";
        }
        else		// error in fetching data from server
        {
            return '<table align="center"><tr><td>Error in fetching data from server</td></tr></table>';
        }
    }
    else	// loading...
    {
        return "";
    }

    // check if we're close to end of cache and need to load more from server to cache
    if ((!this.IsFull) && (this.Children.length - lastIndex < Consts.LAST_ELEMENTS_AMOUNT))
        this.prefetchData();

    // build the window page html		
    containers = this.Children.slice(firstIndex, lastIndex);

    // the containers rows

    for (var i = 0, j = containers.length; i < j; i++) {
        containersHtml += containers[i].getHtml(this.ID);
    }


    // build the pager
    if (this.Children.length > Consts.PAGE_SIZE) {
        var isFirstPage = (pageNumber == 1);
        var isLastPage = (lastIndex == this.Children.length);
        var fromContainer = (pageNumber - 1) * Consts.PAGE_SIZE + 1;
        var toContainer = fromContainer + containers.length - 1;
        var changeToPreviousString = 'changeBranchPage(\'' + this.CacheID + '\',' + (pageNumber - 1) + ');';
        var changeToNextString = 'changeBranchPage(\'' + this.CacheID + '\',' + (pageNumber + 1) + ');';

        containersHtml += ' \
		<div class="Pager"><table align="center"><tr><td> \
			<div class="LinkImage"><div class="Icon ' + (isFirstPage ? ('PagerPrevDimmImage') : ('PagerPrevImage" onclick="' + changeToPreviousString)) + '"></div></div>\
			<div class="Link"><a ' + (isFirstPage ? ('class="disabled" href="#') : (' href="javascript:' + changeToPreviousString)) + '">Prev</a></div>\
			<div class="PageNumbers">' + fromContainer + ' - ' + toContainer + ' of ' + this.NumOfChildren + '</div> \
			<div class="Link"><a ' + (isLastPage ? ('class="disabled" href="#') : (' href="javascript:' + changeToNextString)) + '">Next</a></div>\
			<div class="LinkImage"><div class="Icon ' + (isLastPage ? ('PagerNextDimmImage') : ('PagerNextImage" onclick="' + changeToNextString)) + '"></div></div> \
		</td></tr></table></div>';
    }


    /**** TEMP DEBUG - WHAT THE F*** IS THIS LOOP FOR ****/
    // in the albums branch add the "assets not in album"
    /*
    if (this.BranchType == BranchTypes.ALBUM) {
        console.info('what is this')
        //containersHtml += this.Children[0].getHtml(this.ID);
    }
    */

    return containersHtml;
}

/***		end of Branch object		***/

