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.featTree;
	this.layerReference;
}

Feat.prototype.makeActive = function()
{
         this.isActive = true;
         this.layerReference.childNodes[0].style.backgroundImage = "url(http://www.ageofconan-maps.com/featbuilder/images/" + this.image + ")";
}

Feat.prototype.makeInactive = function()
{
         this.layerReference.childNodes[0].style.backgroundImage = "url(http://www.ageofconan-maps.com/featbuilder/images/off_" + 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 = "http://www.ageofconan-maps.com/featbuilder/images/runes_" + rank + "_" + this.maxRank + ".png";
      trainedImage.style.display = "inline";
      this.rank = rank;
}
Feat.prototype.generateTooltip = function(toolTipLayer)
{
		  rank = this.rank;
		  maxrank = this.maxRank;
 		  row = this.row;
/*		  featReq = this.featReq;
		  namereq = this.ranks[0].name;*/
		  var levelpts=(row)*5;
		  var levelou=levelpts+10;
		  var levelou2=(row-1)*10;
      if(this.rank == 0)
      {
          name = this.ranks[0].name;
          desc = this.ranks[0].desc;
          mod = this.ranks[0].mods;
      }
      else
      {
          name = this.ranks[this.rank-1].name;
          desc = this.ranks[this.rank-1].desc;
          mod = this.ranks[this.rank-1].mods;
      }
      var htmlString =  "<div class=\"featName\">" + name + "</div>";
	   htmlString += "<div class=\"featRank\"><br>Rank "+ rank + "/"+ maxrank + "</div>";
	   if(row==0)
	   {  htmlString += "<table class=\"tabletip\"><tr><td class=\"tipleft\">Condition requise</td><td class=\"tipright\"> Vous devez &ecirc;tre au moins niveau 10</td></tr>"
	   }
	   else if(row<5)
	   {  htmlString += "<table class=\"tabletip\"><tr><td class=\"tipleft\">Condition requise</td><td class=\"tipright\">"+levelpts+" points d&eacute;pens&eacute;s dans cette branche d'aptitudes<br>Vous devez avoir au moins atteint le niveau "+levelou+"</td></tr>"
	   }
	   else
	   {  htmlString += "<table class=\"tabletip\"><tr><td class=\"tipleft\">Condition requise</td><td class=\"tipright\">"+levelpts+" points d&eacute;pens&eacute; dans cette ligne<br>Vous devez avoir au moins atteint le niveau "+levelou2+"</td></tr>"
	   }
/*	   if(featReq!=0)
	   {  htmlString += "<br><span class=\"texttip\" style=\"padding-left:83px\">|  </span><span class=\"underl\">"+namereq+" is requiered</span>"
	    }*/
      if(mod!=undefined)
      {
           for(var i = 0; i < mod.length; i++)
          {
               htmlString += mod[i] + "<br>";
          }
          htmlString += "</td></tr>";
      }
	  htmlString += "</table>";
	  htmlString += "<div class=\"featName\">Description :</div>";
      htmlString += "<div class=\"featDesc\">" + desc + "</div>";
      toolTipLayer.innerHTML = htmlString;
}

function Rank()
{
	this.desc;
	this.name;
	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.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(http://www.ageofconan-maps.com/featbuilder/images/off_" + 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 = "http://www.ageofconan-maps.com/featbuilder/images/runes_" + 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(http://www.ageofconan-maps.com/featbuilder/images/require2.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(http://www.ageofconan-maps.com/featbuilder/images/require1.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(http://www.ageofconan-maps.com/featbuilder/images/require1L.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 = document.getElementById("featDescLayer");
    d.onmouseover = function(e) {
    f.generateTooltip(featDescLayer);
	if (!e) var e = window.event;
        if (e.pageX || e.pageY) 	{
		posx = e.pageX;
		posy = e.pageY;
		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+15;
        featDescLayer.style.left = posx+20;
    };
    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;
		posy = e.pageY;
		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+15;
        featDescLayer.style.left = posx+20;
        };
     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 urlArgs = "?";
     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;
}







