//##############################################################################
//------------------------------------------------------------------------------
function Controller()
{   
    this.howMany = 30;
    this.words = new Array();
    this.incomingWords = new Array();
    this.fillIndex = -1;
    this.focusItem = null;
    this.zoomVelocity = 1;
    this.beenTo = new Array();
    this.loadedIndex = -1;
    this.flickrTagCount = 10;
    this.childScale = 1;
    this.auto = false;
    this.nextAutoTime = 0;
    this.history = new Array();
    this.loadingWordnik = false;
    this.flickrTags = [];
}

//------------------------------------------------------------------------------
Controller.prototype.start = function(initialWord)
{
    if(initialWord)
    {
        var words = initialWord.split(',');
        var count = words.length;
		if(count == 1 && isAcceptableTag(words[0]))
		{
	        controller.addAndGo(words[0]);			
	        this.fillIndex++;
	    }
		else
		{
	        var a;
	        for(a = 0; a < count; a++)
	        {
	            var word = words[a].replace(/ /gi, '');
	            word = word.replace(/\+/gi, '');
	            this.incomingWords.push(cleanTag(word));
	        }
	    }
    }

    var args = 'method=flickr.tags.getHotList&count=200';
    
    getXML(flickrPath + '?args=' + escape(args), parseHotFlickrTags, this, 1);

	this.getWordnikWord();

//    getXML(proxyPath + '?url=http://wordnik.com/feeds/random/100',
  //          parseWords, this, 1);
}

//------------------------------------------------------------------------------
Controller.prototype.update = function()
{
    // ___ Animate Words
    var worldMouse = viewport.worldFromScreen(lastMouse);
    var randomRange = 0.2 * this.childScale;
    var count = this.words.length;
    var a;
    for(a = 0; a < count; a++)
    {
        var entity = this.words[a];
        if(!entity.lockPosition)
        {        
            var item = entity.item;
            if(!item.attached)
                continue;
                
            var multiplier = 1;
			var distance = Math.abs(item.posX - worldMouse.x)
            		+ Math.abs(item.posY - worldMouse.y);
            if(distance < 40)
            	multiplier = distance / 40;
            	
            item.posX = item.posX + (item.velocityX * multiplier);
            item.posY = item.posY + (item.velocityY * multiplier);
            
            item.velocityX -= (item.posX * 0.0001)
                    + ((Math.random() * randomRange) - (randomRange / 2));
            item.velocityY -= (item.posY * 0.0001) 
                    + ((Math.random() * randomRange) - (randomRange / 2));
               
            item.velocityX = Math.min(4, Math.max(-4, item.velocityX));   
            item.velocityY = Math.min(4, Math.max(-4, item.velocityY)); 
            
            if(item == this.focusItem)
                viewport.shiftPan(new Point(item.velocityX, item.velocityY));
        }
        
        entity.update();
    }
    
    // ___ Add More
    if(count < this.flickrTagCount)
        this.addItem();
    
    if(this.fillIndex < this.howMany && !this.focusItem)
    {
        if(this.incomingWords.length)
        {
            var newFillIndex = this.fillIndex + 1;
            
            var item = null;
            if(newFillIndex >= this.words.length)
            {
                if(this.loadedIndex == this.fillIndex)
                    item = this.addItem();
            }
            else
                item = this.words[newFillIndex].item;
                
            if(item)
            {
                var text = this.incomingWords.shift();
                if(text)
                {
                    item.entity.text = text;
                    if(newFillIndex >= this.flickrTagCount)
                        item.entity.startSearches(2);
                    else
                        item.setText(text);
                    
                    this.fillIndex = newFillIndex;
                }
            }
        }
        else
    		this.getWordnikWord();    
    }

    // ___ Auto Zooming
    if(this.zoomVelocity != 1)    
    {
        var center = null;
        if(this.focusItem && this.focusItem.attached)
        {
            var r = this.focusItem.getScreenBounds();
            center = r.getCenter();
        }
        
        viewport.zoom(this.zoomVelocity, center);
    }
    
    // ___ Auto Mode
    if(this.auto)
    {
        var now = getMilliseconds();
        if(this.nextAutoTime < now)
        {   
            var item = this.pickRandomInItem();
            if(this.focusItem)
            {
                var chance = 0.2;
                if(this.focusItem.entity)
                    chance = 0 + Math.min(1, this.focusItem.entity.getDepth() / 19);

                if(Math.random() < chance)
                    item = null;
            }
            
            var beenThere = false;
            if(item)
            {
                beenThere = this.haveBeenTo(item);
                this.handleItemClick(item);
            }
            else
            {
                beenThere = (this.focusItem ? this.haveBeenTo(this.focusItem.parent) : true);
                this.goOut();
            }
            
            if(beenThere)
                this.nextAutoTime = now + 3000;
            else
                this.nextAutoTime = now + 6000;
        }
    }
    
    // ___ Label fading
    if(this.focusItem && this.focusItem.entity && this.focusItem.entity.label)
    {
		var r = this.focusItem.getScreenBounds();
		if(r.containsPoint(lastMouse) && !isPanelUp(helpPanel))
			this.focusItem.entity.fadeInLabel();
		else
			this.focusItem.entity.fadeOutLabel();
	}
	
    // ___ Finish Up
    needsUpdate = true;
}

//------------------------------------------------------------------------------
Controller.prototype.onSearchComplete = function(entity)
{
    var count = this.words.length;
    var index = -1;
    var a;
    for(a = 0; a < count; a++)
    {
        if(entity == this.words[a])
        {
        	index = a;
            break;
        }
    }

	if(entity.items.length)
	{
		entity.item.setText(entity.text);
		if(index != -1)
			this.loadedIndex = Math.max(index, this.loadedIndex);
	}
	else if(entity.item == this.focusItem)
	{
		entity.plantSeed('not found :(', 'tag');
		if(index != -1)
			this.loadedIndex = Math.max(index, this.loadedIndex);
	}
	else
	{
        if(!this.incomingWords.length && this.flickrTags.length)
            this.addIncomingWord(this.flickrTags.shift());
            
		var text = this.incomingWords.shift();
		if(text)
		{
			entity.text = text;
			entity.restartSearches(2);
		}
		else
		    doc.removeItem(entity.item);
	}
}

//------------------------------------------------------------------------------
Controller.prototype.onLoadError = function(service)
{
	if(service == 'Wordnik')
		this.loadingWordnik = true; // Make it not try again
	else
	{
	    var item = this.addItem();
	    item.entity.text = service + ' isn\'t responding; please try again later';
	    item.setText(item.entity.text);
	}
}

//------------------------------------------------------------------------------
Controller.prototype.addItem = function()
{
    var velocityRange = 5 * this.childScale;
    var item = new TextItem('', 10 * this.childScale);
    doc.addItem(item);
    item.posX = 0;
    item.posY = 0;
    item.velocityX = (Math.random() * velocityRange) - (velocityRange / 2);
    item.velocityY = (Math.random() * velocityRange) - (velocityRange / 2);
    
    var word = new Word();
    word.isTag = true;
    word.childScale = this.childScale * entityScaleFactor;
    word.item = item;
    item.entity = word;
    
    this.words.push(word);
    return item;
}

//------------------------------------------------------------------------------
Controller.prototype.addAndGo = function(text)
{
	text = cleanTag(text);
    var item = this.addItem();
    item.entity.text = text;
    item.setText(text);
    
    this.handleItemClick(null, true, true);
    this.handleItemClick(item, true, false);   
}

//------------------------------------------------------------------------------
Controller.prototype.haveBeenTo = function(item)
{
    if(!item)
        return true;
        
    var identifier = item.getIdentifier();
    if(!identifier)
        return true;

    var count = this.beenTo.length;
    var a;
    for(a = 0; a < count; a++)
    {
        if(identifier == this.beenTo[a])
            return true;
    }        
    
    return false;
}

//------------------------------------------------------------------------------
Controller.prototype.startGoingIn = function(item)
{
    this.zoomVelocity = 1.1;
}

//------------------------------------------------------------------------------
Controller.prototype.startGoingOut = function(item)
{
    this.zoomVelocity = 1 / 1.1;
}

//------------------------------------------------------------------------------
Controller.prototype.stopZooming = function(item)
{
    this.zoomVelocity = 1;
}

//------------------------------------------------------------------------------
Controller.prototype.handleItemClick = function(item, clearHistory, immediately)
{
    if(item && item.fontSize && !item.text)
        return;
        
    if(item && !item.entity)
        return;
        
    if(typeof(clearHistory) == 'undefined')
        clearHistory = true;

    if(clearHistory)
        this.history.length = 0;
        
    if(item && item == this.focusItem && item.entity && item.entity.isWord)
        item.entity.loadMore();
    
    this.setFocusItem(item);
    this.goToFocusItem(immediately);
}

//------------------------------------------------------------------------------
Controller.prototype.toggleAuto = function()
{
    this.auto = !this.auto;
    updatePlayButton();
}

//------------------------------------------------------------------------------
Controller.prototype.goIn = function()
{
    var item = this.history.pop();
    if(item)
        this.handleItemClick(item, false);
}

//------------------------------------------------------------------------------
Controller.prototype.goOut = function()
{
    if(this.focusItem)
    {
        this.history.push(this.focusItem);
        this.handleItemClick(this.focusItem.parent, false);
    }
    else
        goToHome();
}

//------------------------------------------------------------------------------
Controller.prototype.pickRandomInItem = function()
{
    var item = null;
    var tries;
    for(tries = 0; tries < 20; tries++)
    {
        if(this.focusItem)
        {
            var entity = this.focusItem.entity;
            if(entity && entity.items.length)
            {
                var index = Math.floor(Math.random() * entity.items.length);
                item = entity.items[index];
            }
            else
                return null;
        }
        else
        {
            var index = Math.floor(Math.random() * this.words.length);
            item = this.words[index].item;
        }
        
        if(!item || !item.attached || !item.isLoaded())
            continue;          
            
        if(this.haveBeenTo(item))
            continue;

        return item;
    }

    return null;
}

//------------------------------------------------------------------------------
Controller.prototype.goInRandomly = function()
{
    var item = this.pickRandomInItem();
    if(item)
        this.handleItemClick(item);
}

//------------------------------------------------------------------------------
Controller.prototype.goToFocusItem = function(immediately)
{
    if(this.focusItem)
    {           
        var fit = 0.6;
        if(this.focusItem.text)
            fit = Math.min(1.0, 0.3 + (this.focusItem.text.length / 30));

        var r = this.focusItem.getBounds();
        viewport.centerOn(r, fit, immediately);
    }
    else
        goToHome(immediately);
}

//------------------------------------------------------------------------------
Controller.prototype.setFocusItem = function(item)
{   
    if(this.focusItem && this.focusItem.entity && this.focusItem.entity.label)
    {
    	this.focusItem.entity.fadeOutLabel();
    	
    	if(hoverItem == this.focusItem)
			this.focusItem.setHighlight(true);
    }

    this.focusItem = item;
    
    if(this.focusItem)
    {
        this.beenTo.push(this.focusItem.getIdentifier());
        
        var entity = this.focusItem.entity;
        var parent = this.focusItem.parent;
        
        if(entity)
        {
            if(this.focusItem == hoverItem && entity.label)
                this.focusItem.setHighlight(false);
    		
        	this.focusItem.opacity = 1;
        	
            entity.lockPosition = true;
            entity.addItems();

            var count = entity.items.length;
            var a;
            for(a = 0; a < count; a++)
            {
                item = entity.items[a];
                if(item.entity)
                    item.entity.removeItems();
            }
        }
            
        if(parent && parent.entity)
        {
            var count = parent.entity.items.length;
            var a;
            for(a = 0; a < count; a++)
            {
                item = parent.entity.items[a];
                if(item != this.focusItem)
                {
                    doc.removeItem(item);
                }
            }
        }
        else
        {
            var count = this.words.length;
            var a;
            for(a = 0; a < count; a++)
            {
                item = this.words[a].item;
                if(item != this.focusItem)
                {
                    doc.removeItem(item);
                }
            }
        }
    }
    else
    {
        var count = this.words.length;
        var a;
        for(a = 0; a < count; a++)
        {
            var entity = this.words[a];
            entity.lockPosition = false;
            entity.removeItems();
            
            item = entity.item;
            if(!item.attached)
                doc.addItem(item);
        }
    }
}

//------------------------------------------------------------------------------
Controller.prototype.getWordnikWord = function()
{
	if(!this.loadingWordnik)
	{
	    this.loadingWordnik = true;
	    getXML(wordnikPath, parseWord, this, 1);
	}
}

//------------------------------------------------------------------------------
Controller.prototype.addIncomingWord = function(word)
{
    //console.log(word);
    var reject = true;
    if(word.indexOf(',') == -1 && word.indexOf('-') == -1 && isAcceptableTag(word))    
    {   
        reject = false;
        word = cleanTag(word);
        //console.log(word);
        
        var a;
        var count = this.words.length;
        for(a = 0; a < count; a++)
        {
            if(this.words[a].text == word)
            {
                reject = true;
                break;
            }
        }

        if(!reject)
        {
            count = this.incomingWords.length;
            for(a = 0; a < count; a++)
            {
                if(this.incomingWords[a] == word)
                {
                    reject = true;
                    break;
                }
            }
        }

        if(!reject)
            this.incomingWords.push(word);
    }

    if(reject)
    {
        word = this.flickrTags.shift();
        if(word)
            this.addIncomingWord(word);
    }            
}

//##############################################################################
//------------------------------------------------------------------------------
function parseWords(http_request, requester)
{
    if(!http_request || !http_request.responseXML)
    {
        requester.onLoadError('Wordnik');
        return;
    }
        
    var file = http_request.responseXML;
	var items = file.getElementsByTagName('item');
	var count = items.length;
    if(!count)
    {
        requester.onLoadError('Wordnik');
        return;
    }

	var a;
	for(a = 0; a < count; a++)
    {
        var word = getXMLData(items[a], 'title');
        if(word.indexOf(',') == -1 && isAcceptableTag(word))       
            requester.incomingWords.push(cleanTag(word));
   	}
}

//------------------------------------------------------------------------------
function parseWord(http_request, requester)
{
	requester.loadingWordnik = false;
	
    if(!http_request || !http_request.responseXML)
    {
        requester.onLoadError('Wordnik');
        return;
    }
        
    var file = http_request.responseXML;
	var items = file.getElementsByTagName('word');
	var count = items.length;
    if(!count)
    {
        requester.onLoadError('Wordnik');
        return;
    }

   	// ___ Turn it into a real array
   	var words = [];
   	var a; 
   	for(a = 0; a < count; a++)
   		words.push(getXMLData(items[a], 'wordstring'));
   		
   	// ___ Grab them randomly, as they come in alphabetized
   	while(words.length)
   	{
        var index = Math.floor(Math.random() * words.length);
        var word = words[index];
        requester.addIncomingWord(word);
        words.splice(index, 1);
    }	
}

//------------------------------------------------------------------------------
function parseHotFlickrTags(http_request, requester)
{
    var file = http_request.responseXML;
    if(!file)
    {
        requester.onLoadError('Flickr');
        return;
    }
    
    var chosen = '';
    var chosenCount = 0;
	var tags = file.getElementsByTagName('tag');
	var count = tags.length;
    if(!count)
    {
        requester.onLoadError('Flickr');
        return;
    }

	var a;
	for(a = 0; a < requester.flickrTagCount * 20; a++)
    {
        var index = Math.floor(Math.random() * count);
        var indexString = '[' + index + ']';
        if(chosen.indexOf(indexString) == -1)
        {
            var word = getXMLData(tags[index]);
            if(isAcceptableTag(word))
            {
                //console.log(word);
				requester.incomingWords.unshift(cleanTag(word));
				requester.loadedIndex++;
				chosen += indexString;
				chosenCount++;
				if(chosenCount >= requester.flickrTagCount)
					break;
			}
        }
    }
    
    for(a = 0; a < count; a++)
    {
        //we won't bother weeding out duplicates now; it'll happen when adding to incomingWords
        requester.flickrTags.push(getXMLData(tags[a]));
    }
}

    