package org.magicnexus.classes.io.xml;

import java.io.File;

import org.magicnexus.classes.data.CardData;
import org.magicnexus.interfaces.EType;
import org.magicnexus.interfaces.data.ICardData;
import org.magicnexus.interfaces.io.xml.ICardParser;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;


public class XmlCardParser extends XmlAbstractCardParser implements ICardParser<XmlException>
{
	
	public XmlCardParser(XmlDataManager manager)
	{
		super(manager, "cards" + File.separator);
	}
	
	@Override
	public ICardData getCard(String cardname) throws XmlException
	{
		return this.parseCard(this.getFileForCard(cardname));
	}
	
	protected File getFileForCard(String cardName)
	{
		return new File(
			this.basePath
			+ Character.toLowerCase(cardName.charAt(0)) + File.separator
			+ cardName.replaceAll("[^\\d\\w]", "_").toLowerCase() + ".xml"
		);
	}
	
	protected ICardData parseCard(File source) throws XmlException
	{
		CardData cdata = new CardData();
		Document dom = this.getDocument(source);
		Element root = dom.getDocumentElement();
		
		for(Node child:this.getChildren(root))
		{
			if(child.getNodeName().equals(CARD_NODE_NAME))
			{
				cdata.setName(child.getTextContent());
			}
			else if(child.getNodeName().equals(CARD_NODE_MANACOST))
			{
				cdata.setManaCost(this.parseManaCost(child.getTextContent()));
			}
			else if(child.getNodeName().equals(CARD_NODE_SURTYPES))
			{
				for(Node node_surtype:this.getChildren(child))
				{
					if(node_surtype.getNodeName().equals(CARD_NODE_SURTYPE))
					{
						cdata.addSurtype(this.parseSurtype(node_surtype.getTextContent()));
					}
					else
						throw new XmlException("Le node "+node_surtype.getNodeName()+" n'est pas un surtype.");
				}
			}
			else if(child.getNodeName().equals(CARD_NODE_TYPES))
			{
				for(Node node_type:this.getChildren(child))
				{
					if(node_type.getNodeName().equals(CARD_NODE_TYPE))
					{
						cdata.addType(this.parseType(node_type.getTextContent()));
					}
					else
						throw new XmlException("Le node "+node_type.getNodeName()+" n'est pas un type.");
				}
			}
			else if(child.getNodeName().equals(CARD_NODE_SUBTYPES))
			{
				for(Node node_subtype:this.getChildren(child))
				{
					if(node_subtype.getNodeName().equals(CARD_NODE_SUBTYPE))
					{
						cdata.addSubtypes(this.parseSubtype(node_subtype.getTextContent()));
					}
					else
						throw new XmlException("Le node "+node_subtype.getNodeName()+" n'est pas un sous-type.");
				}
			}
			else if(child.getNodeName().equals(CARD_NODE_POWER))
			{
				cdata.setPower(this.parsePower(child.getTextContent()));
			}
			else if(child.getNodeName().equals(CARD_NODE_TOUGHNESS))
			{
				cdata.setToughness(this.parseToughness(child.getTextContent()));
			}
			else if(child.getNodeName().equals(CARD_NODE_LOYALTY))
			{
				cdata.setLoyalty(this.parseLoyalty(child.getTextContent()));
			}
			else if(child.getNodeName().equals(CARD_NODE_RULES))
			{
				cdata.setRulesText(child.getTextContent().replace("\t", "").trim());
			}
			else if(child.getNodeName().equals(CARD_NODE_ACTIVATED_ABILITIES))
			{
				for(Node node_activated:this.getChildren(child))
				{
					if(node_activated.getNodeName().equals(CARD_NODE_ACTIVATED_ABILITY))
					{
						cdata.addActivatedAbility(this.parseActivatedAbility(node_activated));
					}
					else
						throw new XmlException("Le node "+node_activated.getNodeName()+" n'est pas une capacité activée.");
				}
			}
			else if(child.getNodeName().equals(CARD_NODE_STATIC_ABILITIES))
			{
				for(Node node_static:this.getChildren(child))
				{
					if(node_static.getNodeName().equals(CARD_NODE_STATIC_ABILITY))
					{
						cdata.addStaticAbility(this.parseStaticAbility(node_static));
					}
					else
						throw new XmlException("Le node "+node_static.getNodeName()+" n'est pas une capacité statique.");
				}
			}
			else if(child.getNodeName().equals(CARD_NODE_TRIGGERED_ABILITIES))
			{
				for(Node node_triggered:this.getChildren(child))
				{
					if(node_triggered.getNodeName().equals(CARD_NODE_TRIGGERED_ABILITY))
					{
						cdata.addTriggeredAbility(this.parseTriggeredAbility(node_triggered));
					}
					else
						throw new XmlException("Le node "+node_triggered.getNodeName()+" n'est pas une capacité déclenchée.");
				}
			}
			else if(child.getNodeName().equals(CARD_NODE_SPELL_ABILITIES))
			{
				for(Node node_spell:this.getChildren(child))
				{
					if(node_spell.getNodeName().equals(CARD_NODE_SPELL_ABILITY))
					{
						cdata.addSpellAbilities(this.parseSpellAbility(node_spell));
					}
					else
						throw new XmlException("Le node "+node_spell.getNodeName()+" n'est pas une capacité de sort.");
				}
			}
			else if(child.getNodeName().equals(CARD_NODE_ALTERNATE_COSTS))
			{
				for(Node node_cost:this.getChildren(child))
				{
					if(node_cost.getNodeName().equals(CARD_NODE_ALTERNATE_COST))
					{
						cdata.addAlternateCost(this.parseAlternateCost(node_cost));
					}
					else
						throw new XmlException("Le node "+node_cost.getNodeName()+" n'est pas un coût alternatif.");
				}
			}
			else
				throw new XmlException("Node inconnu : "+child.getNodeName());
		}
		
		this.checkCardIntegrity(cdata);
		
		return cdata;
	}
	
	protected void checkCardIntegrity(CardData cdata) throws XmlException
	{
		// Some rules :
		// Lands have no mana cost
		// we have to check surtype/type/subtype allowancy
		// creatures have p/ and t/
		// non creatures do not have p/ and t/
		// planeswalkers have l/
		// non planeswalkers do not have l/
		// planeswalkers have between 3 and 4 activated abilities and up to 1 static
		
		if(cdata.getName() == null)
			throw new XmlException("The card doesn't have a name.");
		
		if(cdata.getTypes().isEmpty())
			throw new XmlException("The card doesn't have any type.");
		
		if(cdata.getTypes().contains(EType.LAND))
		{
			if(!cdata.getManaCost().isEmpty())
			{
				throw new XmlException("The card is a land with mana cost");
			}
		}
		// some spells may have no mana cost
		if(cdata.getTypes().contains(EType.CREATURE))
		{
			if(cdata.getPower() == null)
			{
				throw new XmlException("The card is a creature without power");
			}
			if(cdata.getToughness() == null)
			{
				throw new XmlException("The card is a creature without toughness");
			}
		}
		else
		{
			if(cdata.getPower() != null)
			{
				throw new XmlException("The card is a non-creature with power");
			}
			if(cdata.getToughness() != null)
			{
				throw new XmlException("The card is a non-creature with toughness");
			}
		}
		if(cdata.getTypes().contains(EType.PLANESWALKER))
		{
			if(cdata.getLoyalty() == null)
			{
				throw new XmlException("The card is a planeswalker without loyalty");
			}
		}
		else
		{
			if(cdata.getLoyalty() != null)
			{
				throw new XmlException("The card is a non-planeswalker with loyalty");
			}
		}
	}
	
}
