
function Feat(f)
{
	this.featId = f.featId;
	this.levelReq = f.levelReq
	this.rank = 0;
	this.maxRank = f.maxRank;
	this.image = f.image;
	this.featReq = f.featReq;
	this.col = f.col;
	this.row = f.row;
	this.ranks = f.ranks;
	this.isActive = false;
	this.pointsSpent = f.points;
	this.name = f.name;
	this.desc = f.desc;
	this.featTree;
	this.layerReference;
}

Feat.prototype.makeActive = function()
{
         this.isActive = true;
         this.layerReference.childNodes[0].style.backgroundImage = "url(feats/small_Icons/" + this.image + ")";
}

Feat.prototype.makeInactive = function()
{
         this.layerReference.childNodes[0].style.backgroundImage = "url(feats/SW_Icons/sw_" + this.image + ")";
         this.isActive = false;
}

//Checks if feat can be enabled
Feat.prototype.checkReq = function()
{
	if(this.featReq)
	{
		var requiredFeat = this.featTree.findFeat(this.featReq);
		//If not fully skilled, abort
		if(requiredFeat.rank != requiredFeat.maxRank)
		{
                      return false;
                }
	}
        if(this.pointsSpent > this.featTree.usedFeatPoints)
        {
                return false;
        }
	return true;
}
//Check if feat can be untrained
Feat.prototype.isRequirement = function()
{
      //only check lower levels, highest tier is always removable
      if(this.row < this.featTree.maxTier)
      {
            //Add up all feat from this tier and below and check if it fullfills next higher tier
            var sum = 0;
            var overSum = 0;
            for(var i = 0; i < this.featTree.feats.length; i++)
            {
                var feat = this.featTree.feats[i];
                if(feat.row <= this.row)
                {
                      sum += feat.rank;
                }
                else if(feat.row < this.featTree.maxTier)
                {
                      overSum += feat.rank;
                }
            }
            if(sum <= (this.row+1) * 5)
            {
                return true;
            }
            else
            {
                //If next higher tier no problem, check if overall tree till maxTier has enough points
                //alert(this.featTree.maxTier + "," + this.row + "," + (overSum+sum) + "," + sum);
                if(overSum + sum <= this.featTree.maxTier * 5)
                {
                      return true;
                }
            }
      }
      //Is needed as a dependency
      for(var i = 0; i < this.featTree.feats.length; i++)
      {
                if(this.featTree.feats[i].featReq == this.featId)
                {
                      var f = this.featTree.feats[i];
                      if(f.rank != 0)
                      {
                            return true;
                      }
                }
      }
      return false;
}

Feat.prototype.train = function()
{

     //Is trainable
     if(!this.isActive || this.rank >= this.maxRank)
     {
          return;
     }
     //Still have points
     else if(this.featTree.featPlaner.TotalFeatPoints <= 0)
     {
          return;
     }
     //Train it
     //Newly learned => check if applies new upper bound
     if(this.rank == 0)
     {
          if(this.row > this.featTree.maxTier)
          {
                 //Imposes highest feat-side level requirement
                 this.featTree.setMaxTier(this.row);
          }
     }
     this.setRank(this.rank + 1);
     this.featTree.changeFeatPoints(1);
}

Feat.prototype.untrain = function()
{
      if(this.rank == 0)
      {
          return;
      }
      if(this.isRequirement())
      {
          return;
      }
      else
      {
          this.setRank(this.rank-1);
          //Check if maxTier is now lower
          if((this.rank == 0) && (this.row != 0))
          {
               if(this.row == this.featTree.maxTier)
               {
                      var hasNewMaxTier = true;
                      for(var i = 0; i < this.featTree.feats.length; i++)
                      {
                             var feat = this.featTree.feats[i];
                             if((feat.row == this.featTree.maxTier) && (feat.rank > 0))
                             {
                                   hasNewMaxTier = false;
                             }
                      }
                      if(hasNewMaxTier)
                      {
                             this.featTree.setMaxTier(this.featTree.maxTier-1);
                      }
               }
          }
          this.featTree.changeFeatPoints(-1);
      }
}

Feat.prototype.setRank = function(rank)
{
      var rankDiv = this.layerReference.childNodes[1];
      var trainedImage = rankDiv.childNodes[0];

      trainedImage.src = "feats/img/letters_" + rank + "_" + this.maxRank + ".png";
      trainedImage.style.display = "inline";

      this.rank = rank;
}

Feat.prototype.generateTooltip = function(toolTipLayer)
{
	  var rank = null;
	  var nextRank = null;
      if(this.rank == 0)
      {
		  rank = this.ranks[0];
      }
      else if(this.rank < this.maxRank)
      {
		  rank = this.ranks[this.rank-1];
          nextRank = this.ranks[this.rank];
      }
      else
      {
		  rank = this.ranks[this.rank-1];
      }
	  mod = rank.mods;
      var htmlString =  "<div class=\"featName\">" + this.name + "</div>";
      htmlString += "<div class=\"rankName\">Rank " + this.rank + "/" + this.maxRank + "</div>";
      if(mod!=undefined)
      {
          var level = this.featTree.featPlaner.levelSelect.value;
          htmlString += "<div class=\"featMod\">";
          htmlString += generateModString(mod, level);
          htmlString += "</div><br>";
	  }
      if(nextRank!=null)
      {
		   htmlString += "<div class=\"featName\">Next Rank:</div>";
		   htmlString += "<div class=\"rankName\">Rank " + (this.rank+1) + "/" + this.maxRank + "</div>";
		   if(nextRank.mods!=undefined)
		   {
			   htmlString += "<div class=\"featMod\">";
			   htmlString += generateModString(nextRank.mods, level);
			   htmlString += "</div><br>";
		   }
	  }
      htmlString += "<div class=\"featDesc\">";
	  //rank dependent descriptions
	  if(rank.desc != undefined)
	  {
		htmlString += rank.desc;
	  }
	  else
	  {
		htmlString += this.desc;
	  }
	  htmlString += "</div>";
      toolTipLayer.innerHTML = htmlString;
}

function Rank()
{
	this.mods;
}

function FeatTree(f)
{
         this.name = f.name;
         this.feats = f.feats;
         this.usedFeatPoints = 0;
         this.maxTier = 0;
         this.maxLevel = 0;
         this.layerReference;
         this.dependencyLayer;
         this.featPlaner;
}

FeatTree.prototype.setMaxTier = function(tier)
{
         this.maxTier = tier;
         var newMaxLevel = 0;
         for(var i = 0; i < this.feats.length; i++)
         {
                 var feat = this.feats[i];
                 if(feat.row == tier)
                 {
                       newMaxLevel = feat.levelReq;
                       break;
                 }
         }
         this.maxLevel = newMaxLevel;
         this.featPlaner.updateMaxLevel(newMaxLevel);
}

FeatTree.prototype.enableFeats = function()
{
         for(var i = 0; i < this.feats.length; i++)
         {
                var feat = this.feats[i];
                if(feat.checkReq())
                {
                      if(!feat.isActive)
                      {
                            feat.makeActive();
                      }
                }
                else
                {
                      if(feat.isActive)
                      {
                            feat.makeInactive();
                      }
                }
         }
}

FeatTree.prototype.changeFeatPoints = function(amount)
{
         this.usedFeatPoints += amount;
         this.layerReference.childNodes[0].childNodes[1].childNodes[0].innerHTML = this.usedFeatPoints;
         //There are still tiers to explore
         this.enableFeats();

         this.featPlaner.changeTotalPoints(-amount);
}

FeatTree.prototype.setLabel = function(name)
{
         this.layerReference.childNodes[0].childNodes[0].innerHTML = name;
         attachEventsToTree(this.layerReference.childNodes[0].childNodes[1].childNodes[2], this);
}

function attachEventsToTree(elem, tree)
{
         elem.onclick = function()
                 {
                       tree.reset();
                 }
}

FeatTree.prototype.reset = function()
{
         for(var i = 0; i < this.feats.length; i++)
         {
                this.feats[i].makeInactive();
                this.feats[i].setRank(0);
         }
         this.layerReference.childNodes[0].childNodes[1].childNodes[0].innerHTML = 0;
         this.setMaxTier(0);
         this.featPlaner.changeTotalPoints(this.usedFeatPoints);

         this.usedFeatPoints = 0;
         this.enableFeats();
}

FeatTree.prototype.findFeat = function(featId)
{
         for(var i = 0; i < this.feats.length; i++)
         {
                if(this.feats[i].featId == featId)
                {
                      return this.feats[i];
                }
         }
         alert("Feat " + featId + " not found");
}

FeatTree.prototype.complete = function()
{
         for(var i = 0; i < this.feats.length; i++)
         {
                if(this.feats[i].rank == 0 && this.feats[i].isActive)
                {
                      this.feats[i].makeInactive();
                }
         }
}

function FeatPlaner(trees)
{
    this.layoutManager = new LayoutManager();
	this.FeatTrees = trees;
	this.MaxFeatPoints = 79;
	this.TotalFeatPoints = this.MaxFeatPoints;
	this.pointsLayer = document.getElementById("totalPoints");
	this.pointsLayer.innerHTML = this.TotalFeatPoints;
	this.reqLevelLayer = document.getElementById("reqLevel");
	this.linkLayer = document.getElementById("templateLink");
	this.levelSelect = document.getElementById("levelSelect");
	this.pointsLevel = 0;
	this.reqLevel = 0;
}

FeatPlaner.prototype.changeTotalPoints = function(increase)
{
        this.TotalFeatPoints += increase;
        this.pointsLayer.innerHTML = this.TotalFeatPoints;
        this.pointsLevel = this.getLevel();
        this.reqLevelLayer.innerHTML = Math.max(this.pointsLevel, this.reqLevel);
        if(this.TotalFeatPoints == 0)
        {
              for(var i = 0; i < this.FeatTrees.length; i++)
              {
                    this.FeatTrees[i].complete();
              }
        }
        //Untrain, so that points are available again => color feats
        else if((this.TotalFeatPoints == 1) && (increase == 1))
        {
              for(var i = 0; i < this.FeatTrees.length; i++)
              {
                    this.FeatTrees[i].enableFeats();
              }
        }
        //Upgrade link to this build
        this.generateLink();
}

FeatPlaner.prototype.updateMaxLevel = function(level)
{
        if(this.reqLevel < level)
        {
               this.reqLevel = level;
        }
        else
        {
               //Might be that last largest value is gone
               var newMaxLevel = 0;
               for(var i = 0; i < this.FeatTrees.length; i++)
               {
                    var tree = this.FeatTrees[i];
                    if(tree.maxLevel > newMaxLevel)
                    {
                         newMaxLevel = tree.maxLevel;
                    }
               }
               this.reqLevel = newMaxLevel;
        }
}

//Calculates the level at which we can spend to many points
FeatPlaner.prototype.getLevel = function()
{
	var points = this.MaxFeatPoints - this.TotalFeatPoints;
	var levelOffset = 9;
	if(points == 0)
	{
                return 0;
        }

        //A point per level
        if(points > (20 - levelOffset))
        {
             //Extra point at each multiple of ten
             bonusPoints = Math.floor((levelOffset + points-10)/11);
        }
        else
        {
             bonusPoints = 0;
        }
        if(points - bonusPoints + levelOffset > 75)
        {
             bonusPoints++;
        }
        //Take away one at level 79 as its confused by level 75 extra point
        if(points == 78)
        {
             bonusPoints--;
        }

        //Every 11th point for free => 20, 30 ,40 an extra point
	return points - bonusPoints + levelOffset;
}

FeatPlaner.prototype.init = function()
{
        for(var i = 0; i < this.FeatTrees.length; i++)
        {
               this.FeatTrees[i] = new FeatTree(this.FeatTrees[i]);
               var featTree = this.FeatTrees[i];
               featTree.layerReference = document.getElementById("tree_" + i);
               featTree.dependencyLayer = document.getElementById("dependencyLayer_" + i);

               featTree.featPlaner = this;
               featTree.setLabel(featTree.name);
               for(var j = 0; j < featTree.feats.length; j++)
               {
                     featTree.feats[j] = new Feat(featTree.feats[j]);
                     var feat = featTree.feats[j];
                     feat.featTree = featTree;

                     var featDiv = document.createElement('div');
                     featDiv.style.position = "absolute";
                     featDiv.setAttribute("class","feat");
                     featDiv.setAttribute("className","feat");

                     var topOffset = this.layoutManager.topOffset + (feat.row) * (this.layoutManager.featPicSize + this.layoutManager.featRankSize + this.layoutManager.verticalSpacing);
                     var leftOffset = this.layoutManager.leftOffset + (feat.col) * (this.layoutManager.featPicSize + this.layoutManager.horizontalSpacing);
                     featDiv.style.top = topOffset + "px";
                     featDiv.style.left = leftOffset + "px";
                     feat.layerReference = featDiv;

                     var featPicDiv = document.createElement('div');
                     featPicDiv.style.backgroundImage = "url(feats/SW_Icons/sw_" + feat.image + ")";
                     featPicDiv.style.width = this.layoutManager.featPicSize + "px";
                     featPicDiv.style.height = this.layoutManager.featPicSize + "px";
                     attachEventsToDiv(featPicDiv, feat);

                     var rankDiv = document.createElement('div');
                     rankDiv.setAttribute("class","rank");
                     rankDiv.setAttribute("className","rank");


                     var rankImage = document.createElement('img');
                     rankImage.src = "feats/img/letters_" + 0 + "_" + feat.maxRank + ".png";
                     rankDiv.appendChild(rankImage);


                     featDiv.appendChild(featPicDiv);
                     featDiv.appendChild(rankDiv);
                     featTree.layerReference.appendChild(featDiv);

                     //Check dependencies and draw them
                     if(feat.featReq)
                     {
                           var reqFeat = feat.featTree.findFeat(feat.featReq);
                           var deltaCols = (feat.col - reqFeat.col);
                           var deltaRows = (feat.row - reqFeat.row);
                           if(((deltaRows > 0) && (deltaCols == 0)) || ((deltaCols < 2) && (deltaCols > -2) && (deltaRows == 0)))
                           {
                                 deltaCols *= this.layoutManager.horizontalSpacing;
                                 deltaRows = deltaRows * (this.layoutManager.verticalSpacing + this.layoutManager.featRankSize) + (deltaRows-1)* this.layoutManager.featPicSize;
                                 var dependencyDiv = document.createElement('div');
                                 if(deltaRows > 0)
                                 {
                                         dependencyDiv.style.backgroundImage = "url(feats/img/down_two.png)";
                                         dependencyDiv.setAttribute("class","dependencyvert");
                                         dependencyDiv.setAttribute("className","dependencyvert");
                                         dependencyDiv.style.top = (topOffset - deltaRows) + "px";
                                         dependencyDiv.style.left = leftOffset - 9 + this.layoutManager.featPicSize/2 + "px";
                                         dependencyDiv.style.height = deltaRows + "px";
                                 }
                                 else if(deltaCols > 0)
                                 {
                                         dependencyDiv.style.backgroundImage = "url(feats/img/right_one.png)";
                                         dependencyDiv.setAttribute("class","dependencyright");
                                         dependencyDiv.setAttribute("className","dependencyright");
                                         dependencyDiv.style.top = topOffset + "px";
                                         dependencyDiv.style.left = leftOffset + 7 - this.layoutManager.horizontalSpacing + "px";
                                         dependencyDiv.style.width = deltaCols + 4 + "px";
                                 }
                                 else if(deltaCols < 0)
                                 {
                                         dependencyDiv.style.backgroundImage = "url(feats/img/left_one.png)";
                                         dependencyDiv.setAttribute("class","dependencyleft");
                                         dependencyDiv.setAttribute("className","dependencyleft");
                                         dependencyDiv.style.top = topOffset + "px";
                                         dependencyDiv.style.left = leftOffset + this.layoutManager.featPicSize + 7 + "px";
                                         dependencyDiv.style.width = (-1*deltaCols) + 4 +"px";
                                }

                                featTree.dependencyLayer.appendChild(dependencyDiv);
                           }
                     }
               }
               featTree.enableFeats();
        }
}

//Extra function due to closure
function attachEventsToDiv(d, f) {
    var featDescLayer = $('featDescLayer');
    d.onmouseover = function(e) {
        f.generateTooltip(featDescLayer);

        if (!e) var e = window.event;
        if (e.pageX || e.pageY) 	
		{
			posx = e.pageX + 5;
			posy = e.pageY + 5;
			if(posx + 250 > window.innerWidth - 40)
	        {
                posx -= 250;
            }
		}
		else if (e.clientX || e.clientY) 	{
			posx = e.clientX + document.body.scrollLeft
				+ document.documentElement.scrollLeft;
			posy = e.clientY + document.body.scrollTop
				+ document.documentElement.scrollTop;
			if(posx + 250 > document.body.offsetWidth - 40 )
		    {
	                     posx -= 250;
	        }
		}
        featDescLayer.style.display = 'block';
        featDescLayer.style.top = posy+'px';
        featDescLayer.style.left = posx+'px';
    };
    d.onmouseout = function() {
        featDescLayer.style.display = "none";
    };
    d.onmousemove = function(e) {
            if (!e) var e = window.event;
            if (e.pageX || e.pageY) 	{
		posx = e.pageX + 5;
		posy = e.pageY + 5;
		if(posx + 250 > window.innerWidth - 40 )
	        {
                     posx -= 250;
                }
	    }
	    else if (e.clientX || e.clientY) 	{
		posx = e.clientX + document.body.scrollLeft
			+ document.documentElement.scrollLeft;
		posy = e.clientY + document.body.scrollTop
			+ document.documentElement.scrollTop;
		if(posx + 250 > document.body.offsetWidth - 40 )
	        {
                     posx -= 250;
                }
	    }

	    featDescLayer.style.top = posy+'px';;
        featDescLayer.style.left = posx+'px';;
        };
     d.onmousedown = function(e) {
            if (!e) var e = window.event;
            if(e.button == 2)
            {
                f.untrain();
                f.generateTooltip(featDescLayer);
            }
            else
            {
                f.train();
                f.generateTooltip(featDescLayer);
            }
     };
     d.oncontextmenu = function(){
            return false;
     };
}

FeatPlaner.prototype.generateLink = function()
{
     var chunkArray = new Array();
     //Some points spent
     if(this.MaxFeatPoints != this.TotalFeatPoints)
     {
          for(var i = 0; i < this.FeatTrees.length; i++)
          {
               var tree = this.FeatTrees[i];
               for(var j = 0; j < tree.feats.length; j++)
               {
                    var feat = tree.feats[j];
                    if(feat.rank > 0)
                    {
                          var chunkString = feat.featId + '-' + i + feat.rank;
                          chunkArray.push(chunkString);
                    }
               }
          }
     }
     var linkString = chunkArray.join(",");
     var lgSelect = document.getElementById("langSelect");
     var csSelect = document.getElementById("classSelect");
     var urlArgs = "?class=" + csSelect.value + "&lang=" + lgSelect.value;
     if(linkString!="")
     {
           urlArgs += ("&temp=" + linkString);
     }
     this.linkLayer.value = document.URL.split("?")[0]+urlArgs;
}

FeatPlaner.prototype.loadTemplate = function(templateString)
{
     var chunks = templateString.split(",");
     for(var i = 0; i < chunks.length; i++)
     {
          var chunkParts = chunks[i].split("-");
          var featId = chunkParts[0];
          var tree = parseInt(chunkParts[1].charAt(0));
          var rank = parseInt(chunkParts[1].charAt(1));
          var feat = this.FeatTrees[tree].findFeat(featId);
          
          if(feat.rank == 0)
          {
                 if(feat.row > feat.featTree.maxTier)
                 {
                        //Imposes highest feat-side level requirement
                        feat.featTree.setMaxTier(feat.row);
                 }
          }
          feat.setRank(rank);
          feat.makeActive();
          feat.featTree.changeFeatPoints(rank);
     }
}

function LayoutManager()
{
         this.leftOffset = 0;
         this.topOffset = 28;
         this.horizontalSpacing = 20;
         this.verticalSpacing = 8;
         this.featPicSize = 38;
         this.featRankSize = 18;
}
