/*
 * Copyright
 *   2007 axYus - www.axyus.com
 *   2009 C.Marchand - christophe.marchand@axyus.com
 *   2009 JP.Tessier - jean-philippe.tessier@axyus.com
 *
 * This file is part of XEMELIOS.
 *
 * XEMELIOS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * XEMELIOS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with XEMELIOS; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package fr.gouv.finances.dgfip.xemelios.cg.linkResolver;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Properties;
import java.util.Vector;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;

import fr.gouv.finances.dgfip.utils.NavigationContext;
import fr.gouv.finances.dgfip.utils.Pair;
import fr.gouv.finances.dgfip.utils.xml.transform.CustomURIResolver;
import fr.gouv.finances.dgfip.xemelios.auth.XemeliosUser;
import fr.gouv.finances.dgfip.xemelios.common.config.DocumentModel;
import fr.gouv.finances.dgfip.xemelios.common.config.ElementModel;
import fr.gouv.finances.dgfip.xemelios.common.config.EtatModel;
import fr.gouv.finances.dgfip.xemelios.common.config.Loader;
import fr.gouv.finances.dgfip.xemelios.common.config.customLinks.CustomLinkParameters;
import fr.gouv.finances.dgfip.xemelios.common.config.customLinks.CustomLinkResolver;
import fr.gouv.finances.dgfip.xemelios.common.config.customLinks.UnresolvedException;
import fr.gouv.finances.dgfip.xemelios.data.DataConfigurationException;
import fr.gouv.finances.dgfip.xemelios.data.DataImpl;
import fr.gouv.finances.dgfip.xemelios.data.DataLayerManager;

/**
 *
 * @author chm
 */
public class CGCustomLinkResolver extends CustomLinkResolver {
	private static final Logger logger = Logger.getLogger(CGCustomLinkResolver.class);

	private Properties xslParameters = new Properties(); 
	
	public CGCustomLinkResolver() {
		super();
		logger.debug("instanciating");
	}

	@Override
	public NavigationContext resolve(CustomLinkParameters parameters,Result result, NavigationContext ctx, XemeliosUser user) throws DataConfigurationException, UnresolvedException {
		logger.debug("in resolve(CustomLinkParameters,Result,NavigationContext,XemeliosUser)");
		//Hashtable<String,String> hParams = new Hashtable<String,String>();
//		for(String key:parameters.getParameters().keySet()) {
//			System.out.println("++ Parameter initiaux ("+key+","+parameters.getParameter(key)+")");
//		}
		if(parameters.getParameter("form") != null && parameters.getParameter("form").equals("page")){
			treatGoto(parameters,ctx, user);
			commonTreatment(parameters,ctx,result,user);
		} else {
			if(parameters.getParameter("navigation")!=null && Boolean.parseBoolean(parameters.getParameter("navigation")) && parameters.getSrcDocId().equals("compteGestion")){
				treatNavigation(parameters,ctx, user);
				commonTreatment(parameters,ctx,result,user);
			} else if(parameters.getSrcDocId().equals("compteGestion") && parameters.getSrcEtatId().equals("BalanceGenerale")){
				treatBalanceGenerale(parameters,ctx);
				commonTreatment(parameters,ctx,result,user);    		
			} else if(parameters.getSrcDocId().equals("compteGestion") && parameters.getSrcEtatId().equals("FichesBudgetaires")){
				treatFichesBudgetaires(parameters,ctx);
				commonTreatment(parameters,ctx,result,user);
			} else if(parameters.getSrcDocId().equals("compteGestion") && parameters.getSrcEtatId().equals("Accueil")){
				treatAccueil(parameters,ctx, user);
				commonTreatment(parameters,ctx,result,user);
			}
		}
		return ctx;
	}

	private void commonTreatment(CustomLinkParameters parameters, NavigationContext ctx, Result result, XemeliosUser user) throws UnresolvedException,DataConfigurationException {
		logger.debug("in commontTreatment(CustomLinkParameters,NavigationContext,Result,XemeliosUser)");
		try{
			DataImpl impl = DataLayerManager.getImplementation();
			DocumentModel dm = Loader.getDocumentsInfos(null).getDocumentById(ctx.getDocId());
			EtatModel em = dm.getEtatById(ctx.getEtatId());
			ElementModel element = em.getElementById(ctx.getElementId());
			File xslFile = null;
			xslFile = new File(new File(new File(System.getProperty("user.home")),"xemelios/documents-def-ovrrd"),element.getXslt());
			if(!xslFile.exists()) xslFile = new File(em.getParent().getBaseDirectory(),element.getXslt());

			FileInputStream fis = new FileInputStream(xslFile);
			String docId = null;
			if(ctx.getPath()==null) {
				ArrayList<String> documents = impl.getDocumentListFromSpecialKeys(element,ctx.getCollectivite(),ctx.getBudget(),ctx.getSp1(),ctx.getSp2(),ctx.getSp3(),user);
				if(documents.size()==0) {
					throw new UnresolvedException("Le document est introuvable.");
				} else if(documents.size()>1 && !em.isMultiPage()) {
					throw new UnresolvedException("Plusieurs documents répondant à ces critères ont été trouvés.");
				} else {
					docId = documents.get(0);
				}
			} else {
				if(ctx.getElementId()==null) {
					ctx.setElementId(element.getId());
				}
				if(ctx.getPath()!=null && ctx.getPath().startsWith("[")) {
					ctx.setPath(element.getPath().getFormattedPath()+ctx.getPath());
				}
				ArrayList<String> documents = impl.getDocumentListFromXPath(element,ctx.getCollectivite(),ctx.getBudget(),ctx.getSp1(),ctx.getSp2(),ctx.getSp3(),ctx.getPath(), user);
				if(documents.size()==0 && parameters.getParameter("compte")!=null) {
					throw new UnresolvedException("Ce compte n'est associé a aucun(e) "+ctx.getEtatId()+".");
				} else if(documents.size()==0 && parameters.getParameter("page")!=null){
					throw new UnresolvedException("Cette page n'est associée a aucun(e) "+ctx.getEtatId()+".");
				}else if(documents.size()>1){
					docId=documents.get(0);
				} else {
					if(documents.size()>0){
						docId=documents.get(0);
					} else {
						throw new UnresolvedException("Ce compte n'est associé a aucun(e) "+ctx.getEtatId()+".");
					}
				}
			}

			Document doc = impl.getDocumentAsDom(em,new Pair(ctx.getCollectivite(),null),new Pair(ctx.getBudget(),null),docId , user);
			TransformerFactory tFactory = net.sf.saxon.TransformerFactoryImpl.newInstance();
			tFactory.setURIResolver(new CustomURIResolver(tFactory.getURIResolver(), xslFile.getParentFile().toURI().toURL().toExternalForm()));
			Transformer t = tFactory.newTransformer(new StreamSource(xslFile));
			for(String key:parameters.getParameters().keySet()) {
				if(key.startsWith("xsl:param")) {
					String paramValue = parameters.getParameter(key);
					int virg = paramValue.indexOf(',');
					String pName = paramValue.substring(1,virg);
					String pValue = paramValue.substring(virg+1,paramValue.length()-1);
					t.setParameter(pName, pValue);
//System.out.println("++ addParameter("+pName+","+pValue+")");
				}
			}
			for(Object o:getXslParameters().keySet()) {
				String key = (String) o;
				String paramValue = getXslParameters().getProperty(key);
				//int virg = paramValue.indexOf(',');
				//String pName = paramValue.substring(1,virg);
				//String pValue = paramValue.substring(virg+1,paramValue.length()-1);
				if(t.getParameter(key)==null){
					t.setParameter(key, paramValue);
//					System.out.println("++ addParameterAdditional("+key+","+paramValue+")");
				}
			}
			
			t.transform(new DOMSource(doc),result);
		} catch(UnresolvedException unEx) {
			throw unEx;
		} catch (Exception e) {
			logger.error("commontTreatment(CustomLinkParameters,NavigationContext,Result,XemeliosUser)",e);
			throw new DataConfigurationException(e);
		}
	}

	private void treatBalanceGenerale(CustomLinkParameters parameters,NavigationContext ctx){
		try{
			logger.debug("in treatBalanceGenerale(CustomLinkParameters parameters,NavigationContext ctx)");
			DocumentModel dm = Loader.getDocumentsInfos(null).getDocumentById(parameters.getSrcDocId());
			String baseDir = dm.getBaseDirectory();
			File f = new File(baseDir,dm.getParameters().getParameter("liens.balance").getValue());
			DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			Document LiensBalance = db.parse(f);

			String CodRD= (parameters.getParameter("CodRD")!=null)?parameters.getParameter("CodRD"):"";
			String numCompte = parameters.getParameter("numCompte");

			ctx.setDocId("compteGestion");
			if(parameters.getSrcCollectivite() != null){
				ctx.setCollectivite(parameters.getSrcCollectivite());
			}
			if(parameters.getSrcBudget() != null){
				ctx.setBudget(parameters.getSrcBudget());
			}
			if(parameters.getParameter("sp1") != null){
				ctx.setSp1(parameters.getParameter("sp1"));
			}
			if(parameters.getParameter("sp2") != null){
				ctx.setSp2(parameters.getParameter("sp2"));
			}
			if(parameters.getParameter("sp3") != null){
				ctx.setSp3(parameters.getParameter("sp3"));
			}

			String budgetBA = parameters.getParameter("BudgetBA");
			String siretBA = parameters.getParameter("SiretBA");
			
			if(numCompte != null) { 
				if(numCompte.startsWith("1")){   // Compte de classe 1
					ctx.setEtatId("FichesBudgetaires");
					ctx.setElementId("PageFichesBudgetaires");
					ctx.setPath("[n:EnteteFichesBudgetaires/@NumCompte="+numCompte+"][n:EnteteFichesBudgetaires/@CodRD="+CodRD+"]"+getPathBudgetAnnexe(budgetBA,siretBA));

				} else if(numCompte.startsWith("2")){  // Compte de classe 2		
					ctx.setEtatId("FichesBudgetaires");
					ctx.setElementId("PageFichesBudgetaires");
					ctx.setPath("[n:EnteteFichesBudgetaires/@NumCompte="+numCompte+"][n:EnteteFichesBudgetaires/@CodRD="+CodRD+"]"+getPathBudgetAnnexe(budgetBA,siretBA));

				} else if((numCompte.startsWith("4") || numCompte.startsWith("5")) && (!numCompte.startsWith("48") && !numCompte.startsWith("49"))){  // Compte de classe 4  ou 5      		
					XPath xp = XPathFactory.newInstance().newXPath();	    	
					String compteGestion = parameters.getParameter("cg");
					String typeLien = parameters.getParameter("type");

					String etatSolde = xp.evaluate("/Editions/Comptes[@Edition='"+compteGestion+"']/Compte[@Numero='"+numCompte+"']/@Solde",LiensBalance.getDocumentElement());	    	
					String etatDebit = xp.evaluate("/Editions/Comptes[@Edition='"+compteGestion+"']/Compte[@Numero='"+numCompte+"']/@Debit",LiensBalance.getDocumentElement());
					String etatCredit = xp.evaluate("/Editions/Comptes[@Edition='"+compteGestion+"']/Compte[@Numero='"+numCompte+"']/@Credit",LiensBalance.getDocumentElement());

					if(etatSolde!=null && !etatSolde.equals("") && typeLien.equals("solde")){
						String path = "";
						if(etatSolde.equals("ERAR") || etatSolde.equals("ERAP")){
							if(etatSolde.equals("ERAR")){
								path += "[n:EnteteSolde/@Type='RAR']";
							}else{
								path += "[n:EnteteSolde/@Type='RAP']";		    					
							}
							etatSolde="Solde";
						}
						ctx.setEtatId(etatSolde);
						ctx.setElementId("Page"+etatSolde);

						path += "[n:Entete"+etatSolde+"/@NumCompte="+numCompte+"]";
						if(CodRD!=null && !CodRD.equals("") && !etatSolde.equals("DeveloppementSoldes") && !etatSolde.equals("Solde") && !etatSolde.equals("LivreAuxiliaire")){
							path += "[n:Entete"+etatSolde+"/@CodRD="+CodRD+"]";
						}
						ctx.setPath(path+getPathBudgetAnnexe(budgetBA,siretBA));
					}else if(etatCredit!=null && !etatCredit.equals("") && typeLien.equals("totaux") && CodRD!=null && CodRD.equals("R")){
						String path = "";
						if(etatCredit.equals("ERAR") || etatCredit.equals("ERAP")){
							if(etatCredit.equals("ERAR")){
								path += "[n:EnteteSolde/@Type='RAR']";
							}else{
								path += "[n:EnteteSolde/@Type='RAP']";		    					
							}
							etatCredit="Solde";							
						}
						ctx.setEtatId(etatCredit);
						ctx.setElementId("Page"+etatCredit);

						path += "[n:Entete"+etatCredit+"/@NumCompte="+numCompte+"]";
						if(CodRD!=null && !CodRD.equals("") && !etatCredit.equals("DeveloppementSoldes") && !etatCredit.equals("Solde") && !etatCredit.equals("LivreAuxiliaire")){
							path += "[n:Entete"+etatCredit+"/@CodRD="+CodRD+"]";
						}
						ctx.setPath(path+getPathBudgetAnnexe(budgetBA,siretBA));
					}else if(etatDebit!=null && !etatDebit.equals("") && typeLien.equals("totaux") && CodRD!=null && CodRD.equals("D")){
						String path = "";
						if(etatDebit.equals("ERAR") || etatDebit.equals("ERAP")){
							if(etatDebit.equals("ERAR")){
								path += "[n:EnteteSolde/@Type='RAR']";
							}else{
								path += "[n:EnteteSolde/@Type='RAP']";		    					
							}
							etatDebit="Solde";
						}
						ctx.setEtatId(etatDebit);
						ctx.setElementId("Page"+etatDebit);

						path += "[n:Entete"+etatDebit+"/@NumCompte="+numCompte+"]";
						if(CodRD!=null && !CodRD.equals("") && !etatDebit.equals("DeveloppementSoldes") && !etatDebit.equals("Solde") && !etatDebit.equals("LivreAuxiliaire")){
							path += "[n:Entete"+etatDebit+"/@CodRD="+CodRD+"]";
						}
						ctx.setPath(path+getPathBudgetAnnexe(budgetBA,siretBA));
					} else {
						ctx.setEtatId("LivreAuxiliaire");
		    			ctx.setElementId("PageLivreAuxiliaire");
		    			ctx.setPath("[n:EnteteLivreAuxiliaire/@NumCompte="+numCompte+"]"+getPathBudgetAnnexe(budgetBA,siretBA));
					}
				} else if(numCompte.startsWith("48")){  // Compte de classe 48
					ctx.setEtatId("FichesBudgetaires");
					ctx.setElementId("PageFichesBudgetaires");
					if(numCompte.contains("9")){
						CodRD="R";
					}else{
						CodRD="D";
					}
					ctx.setPath("[n:EnteteFichesBudgetaires/@NumCompte="+numCompte+"][n:EnteteFichesBudgetaires/@CodRD="+CodRD+"]"+getPathBudgetAnnexe(budgetBA,siretBA));
				} else if(numCompte.startsWith("49")){  // Compte de classe 49
					ctx.setEtatId("FichesBudgetaires");
					ctx.setElementId("PageFichesBudgetaires");
					if(numCompte.contains("9")){
						CodRD="R";
					}else{
						CodRD="D";
					}
					ctx.setPath("[n:EnteteFichesBudgetaires/@NumCompte="+numCompte+"][n:EnteteFichesBudgetaires/@CodRD="+CodRD+"]"+getPathBudgetAnnexe(budgetBA,siretBA));
				} else if(numCompte.startsWith("6")){  // Compte de classe 6
					ctx.setEtatId("FichesBudgetaires");
					ctx.setElementId("PageFichesBudgetaires");
					if(numCompte.contains("9")){
						CodRD="R";
					}else{
						CodRD="D";
					}
					ctx.setPath("[n:EnteteFichesBudgetaires/@NumCompte="+numCompte+"][n:EnteteFichesBudgetaires/@CodRD="+CodRD+"]"+getPathBudgetAnnexe(budgetBA,siretBA));
				} else if(numCompte.startsWith("7")){  // Compte de classe 7
					ctx.setEtatId("FichesBudgetaires");
					ctx.setElementId("PageFichesBudgetaires");
					if(numCompte.contains("9")){
						CodRD="D";
					}else{
						CodRD="R";
					}
					ctx.setPath("[n:EnteteFichesBudgetaires/@NumCompte="+numCompte+"][n:EnteteFichesBudgetaires/@CodRD="+CodRD+"]"+getPathBudgetAnnexe(budgetBA,siretBA));
				}
			}
		} catch (Exception e){
			e.printStackTrace();
		}
	}

	private String getPathBudgetAnnexe(String budgetBA, String siretBA){
		return (((budgetBA!=null && budgetBA.length()==2)?"[@added:BudgetBA="+budgetBA+"]":"")+((siretBA!=null && siretBA.length()==14)?"[@added:SiretBA="+siretBA+"]":""));
	}
	
	private void treatFichesBudgetaires(CustomLinkParameters parameters,NavigationContext ctx) throws UnresolvedException {
		try{
			//String numeroTypePiece = parameters.getParameter("numeroTypePiece");
			String codRD = parameters.getParameter("codRD");
			String exercice = parameters.getParameter("exercice");
			String mtEmis = parameters.getParameter("mtEmis");
			String mtAnn = parameters.getParameter("mtAnn");
            String mandatId = parameters.getParameter("mandatId");

			/*DocumentModel dm = MainWindow.getInstance().getDocModels().getDocumentById(parameters.getSrcDocId());
			EtatModel em = dm.getEtatById(parameters.getSrcEtatId());

			File f = new File(em.getParent().getBaseDirectory(),"cg-m14/TypesBordereaux.xml");
			DocumentBuilder domParser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
	        Document typesBordereaux = domParser.parse(new FileInputStream(f));

	        XPath xp = XPathFactory.newInstance().newXPath();
	        Object pieces = null;
	        if(codRD.equals("D")){
	        	pieces = xp.evaluate("//Depense/Correspondance/Piece", typesBordereaux.getDocumentElement(), XPathConstants.NODESET);
	        }else{
	        	pieces = xp.evaluate("//Recette/Correspondance/Piece", typesBordereaux.getDocumentElement(), XPathConstants.NODESET);
	        }
	        Vector<String> typeBordereau = new Vector<String>();

	        if(pieces instanceof NodeList) {
		        NodeList nl = (NodeList)pieces; 
		        for(int i=0;i<nl.getLength();i++) {
		            Element piece = (Element)nl.item(i);
		            String libellePiece = piece.getAttribute("Libelle");
		            String codePiece = piece.getAttribute("Code");
		            if(numeroTypePiece.toLowerCase().contains(libellePiece.toLowerCase())){
		            	if(!codePiece.equals("13") && !codePiece.equals("14")){
		            		typeBordereau.add(piece.getParentNode().getAttributes().getNamedItem("TypeBordereauCode").getNodeValue());
		            	} else {
		            		if(mtEmis!=null && mtEmis.length()>0){
		            			typeBordereau.add("01");
		            		} else if(mtAnn!=null && mtAnn.length()>0){
		            			typeBordereau.add("02");
		            		}
		            	}
		            }
		        }
	        } else if(pieces instanceof List) {
	        	for(Element piece: (List<Element>)pieces) {
	        		String libellePiece = piece.getAttribute("Libelle");
	        		String codePiece = piece.getAttribute("Code");
	        		if(!codePiece.equals("13") && !codePiece.equals("14")){
	            		typeBordereau.add(piece.getParentNode().getAttributes().getNamedItem("TypeBordereauCode").getNodeValue());
	            	} else {
	            		if(mtEmis!=null && mtEmis.length()>0){
	            			typeBordereau.add("01");
	            		} else if(mtAnn!=null && mtAnn.length()>0){
	            			typeBordereau.add("02");
	            		}
	            	}
	        	}
	        }*/
			//logger.debug(this.getClass().getName()+" : Type Bordereau = "+typeBordereau.get(0));

			ctx.setDocId("PES_Aller");
			if(codRD.equals("D")){
				ctx.setEtatId("PES_DepenseAller");
				ctx.setElementId("Piece");
			}else{
				ctx.setEtatId("PES_RecetteAller");
				ctx.setElementId("PieceRecette");
			}

			if(parameters.getSrcCollectivite() != null){
				ctx.setCollectivite(parameters.getSrcCollectivite());
			}
			if(parameters.getSrcBudget() != null){
				ctx.setBudget(parameters.getSrcBudget());
			}
			if(ctx.getSp1() != null){
				//ctx.resetSp1();
				ctx.setSp1(null);
			}
			String typeBordereau ="";
			if(mtEmis!=null && mtEmis.length()>0){
				typeBordereau="01";
			} else if(mtAnn!=null && mtAnn.length()>0){
				typeBordereau="02";
			}
//			ctx.setPath("[n:BlocBordereau/n:Exer/@V="+exercice+"][n:BlocBordereau/n:TypBord/@V="+typeBordereau+"]");
            StringBuffer path = new StringBuffer();
            path.append("[../n:BlocBordereau/n:Exer/@V=").append(exercice).append("][../n:BlocBordereau/n:TypBord/@V=").append(typeBordereau).append("]");
            if("D".equals(codRD)) {
                path.append("[n:BlocPiece/n:InfoPce/n:IdPce/@V=").append(mandatId).append("]");
            } else {
                path.append("[n:BlocPiece/n:IdPce/@V=").append(mandatId).append("]");
            }
            ctx.setPath(path.toString());
		} catch (Exception e) {
			logger.debug("Erreur", e);
			throw new UnresolvedException("treatFichesBudgetaires(CustomLinkParameters parameters,NavigationContext ctx)");
		}
	}

	private void treatGoto(CustomLinkParameters parameters,NavigationContext ctx, XemeliosUser user) throws UnresolvedException {
		try{
			DocumentModel dm = Loader.getDocumentsInfos(null).getDocumentById(parameters.getSrcDocId());
			EtatModel em = dm.getEtatById(parameters.getSrcEtatId());
			ElementModel elm = em.getElementById(parameters.getSrcElementId());
			DataImpl impl = DataLayerManager.getImplementation();
			
			Pair collectivite = new Pair(parameters.getParameter("srcCollectiviteCode"),parameters.getParameter("srcCollectiviteLibelle"));
			Pair budget = null;
			Vector<Pair> budgets = impl.getBudgets(dm, collectivite, user);
			for(Pair budg:budgets){
				if(budg.key.equals(parameters.getParameter("srcBudgetCode"))){
					budget=budg;
				}
			}
			
			int numPage = parameters.getParameter("page")!=null?Integer.parseInt(parameters.getParameter("page")):-1;
			int compte = parameters.getParameter("compte")!=null?Integer.parseInt(parameters.getParameter("compte")):-1;
			
			ctx.setDocId(parameters.getSrcDocId());
			ctx.setEtatId(em.getBalise());
			ctx.setElementId(elm.getBalise());
			ctx.setCollectivite(collectivite.key);
			ctx.setBudget(budget.key);
			
			String budgetBA = parameters.getParameter("BudgetBA");
			String siretBA = parameters.getParameter("SiretBA");
			String pathSecondaire = "";
			
			Pair pairBA = new Pair(siretBA,budgetBA);
			
			if(parameters.getParameter("sp1") != null){
				ctx.setSp1(parameters.getParameter("sp1"));
			}
			if(parameters.getParameter("sp2") != null){
				ctx.setSp2(parameters.getParameter("sp2"));
			}
			if(parameters.getParameter("sp3") != null){
				ctx.setSp3(parameters.getParameter("sp3"));
			}
			if(getPathBudgetAnnexe(pairBA.libelle, pairBA.key) != null && getPathBudgetAnnexe(pairBA.libelle, pairBA.key).length() > 0){
				
				pathSecondaire+=getPathBudgetAnnexe(pairBA.libelle, pairBA.key);
			} else {
				if(isEtatSpecial(elm.getBalise())) pathSecondaire+="[@added:BudgetBA='']";
			}
			if(parameters.getParameter("pathplus") != null){
				pathSecondaire+=parameters.getParameter("pathplus");
			}
			
			if(numPage!=-1){
				logger.debug("in treatGoto(CustomLinkParameters parameters,NavigationContext ctx) : Type=Page");
				
				if(parameters.getParameter("path") != null){
					ctx.setPath(parameters.getParameter("path").replace("%page%", String.valueOf(numPage)));
				}
				
				if(siretBA!=null && siretBA.length() > 0){
					ctx.setPath((ctx.getPath()==null?"":ctx.getPath())+pathSecondaire);
				} else {
					ArrayList<String> docs = impl.getDocumentListFromSpecialKeys(elm, parameters.getParameter("srcCollectiviteCode"), parameters.getParameter("srcBudgetCode"), parameters.getParameter("sp1"), null, null, user);
					Document doc = impl.getDocumentAsDom(em, collectivite, budget, docs.get(0), user);
					
					XPath xp = XPathFactory.newInstance().newXPath();
					xp.setNamespaceContext(dm.getNamespaces());
					
					String firstPage = (String) xp.evaluate("//n:LigneSommaire[@Code='"+em.getBalise()+"']/@FirstPage",doc.getDocumentElement(), XPathConstants.STRING);
					String lastPage = (String) xp.evaluate("//n:LigneSommaire[@Code='"+em.getBalise()+"']/@LastPage",doc.getDocumentElement(), XPathConstants.STRING);
					String firstPageCG = (String) xp.evaluate("//n:FirstPageCG/@V",doc.getDocumentElement(), XPathConstants.STRING);
					String lastPageCG = (String) xp.evaluate("//n:LastPageCG/@V",doc.getDocumentElement(), XPathConstants.STRING);
					
					if(lastPageCG !=null && lastPageCG.length() > 0 && numPage > Integer.parseInt(lastPageCG)){
						throw new UnresolvedException("La page recherchée est inexistante.\nLe Compte de Gestion finit à la page "+lastPageCG+".");
					}if(firstPageCG !=null && firstPageCG.length() > 0 && numPage < Integer.parseInt(firstPageCG)){
						throw new UnresolvedException("La page recherchée est inexistante.\nLe Compte de Gestion commence à la page "+firstPageCG+".");
					} else {
						if(firstPage !=null && lastPage !=null && firstPage.length() > 0 && lastPage.length() > 0 && (numPage<Integer.parseInt(firstPage) || numPage>Integer.parseInt(lastPage))){
							String etat = (String) xp.evaluate("//n:LigneSommaire["+numPage+" >= @FirstPage and "+numPage+" <= @LastPage]/@Code",doc.getDocumentElement(), XPathConstants.STRING);
							ctx.setEtatId(etat);
							ctx.setElementId("Page"+etat);
							if(parameters.getParameter("path") != null){
								ctx.setPath(parameters.getParameter("path").replace("%page%", String.valueOf(numPage)));
							}
						}
					}
				}
			} else if(compte!=-1){
				logger.debug("in treatGoto(CustomLinkParameters parameters,NavigationContext ctx) : Type=Compte");
				
				if(parameters.getParameter("path") != null){
					String path = "";
					if(parameters.getParameter("compte")!=null) path+=parameters.getParameter("path").replace("%compte%", String.valueOf(compte));
					if(parameters.getParameter("codrd")!=null) path+=parameters.getParameter("path").replace("%codrd%", parameters.getParameter("codrd"));
					ctx.setPath(path);
				}
				ctx.setPath((ctx.getPath()==null?"":ctx.getPath())+pathSecondaire);
			}
		} catch (Exception e) {
			if(e instanceof UnresolvedException){
				throw (UnresolvedException)e;
			} else {
				logger.debug("Erreur", e);
				throw new UnresolvedException("treatGotoPage(CustomLinkParameters parameters,NavigationContext ctx)");
			}
		}
	}
	
	private void treatNavigation(CustomLinkParameters parameters,NavigationContext ctx, XemeliosUser user) throws UnresolvedException {
		try{
			logger.debug("in treatNavigation(CustomLinkParameters parameters,NavigationContext ctx)");

			DocumentModel dm = Loader.getDocumentsInfos(null).getDocumentById(parameters.getSrcDocId());
			EtatModel em = dm.getEtatById(parameters.getSrcEtatId());
			ElementModel elm = em.getElementById(parameters.getSrcElementId());
			DataImpl impl = DataLayerManager.getImplementation();
			
			ctx.setDocId(parameters.getSrcDocId());
			ctx.setEtatId(parameters.getSrcEtatId());
			ctx.setElementId(parameters.getSrcElementId());
			
			int numPage = Integer.parseInt(parameters.getParameter("numPage"));
			String sensNavigation = parameters.getParameter("sens");
			if(sensNavigation==null) sensNavigation="";
			
			Pair collectivite = new Pair(parameters.getSrcCollectivite() ,parameters.getParameter("srcCollectiviteLibelle"));
			Pair budget = null;
			Vector<Pair> budgets = impl.getBudgets(dm, collectivite, user);
			for(Pair budg:budgets){
				if(budg.key.equals(parameters.getSrcBudget())){
					budget=budg;
				}
			}
		
			ctx.setCollectivite(collectivite.key);
			ctx.setBudget(budget.key);
			
			String budgetBA = parameters.getParameter("BudgetBA");
			String siretBA = parameters.getParameter("SiretBA");
			String pathSecondaire = "";
			
			Pair pairBA = new Pair(siretBA,budgetBA);
			
			if(parameters.getParameter("sp1") != null){
				ctx.setSp1(parameters.getParameter("sp1"));
			}
			if(parameters.getParameter("sp2") != null){
				ctx.setSp2(parameters.getParameter("sp2"));
			}
			if(parameters.getParameter("sp3") != null){
				ctx.setSp3(parameters.getParameter("sp3"));
			}
			if(parameters.getParameter("path") != null){
				ctx.setPath(parameters.getParameter("path").replace("%page%", String.valueOf(numPage)));
			}
			if(getPathBudgetAnnexe(pairBA.libelle, pairBA.key) != null && getPathBudgetAnnexe(pairBA.libelle, pairBA.key).length() > 0){
				pathSecondaire+=getPathBudgetAnnexe(pairBA.libelle, pairBA.key);
			} else {
				if(isEtatSpecial(elm.getBalise())) pathSecondaire+="[@added:BudgetBA='']";
			}
			if(parameters.getParameter("pathplus") != null){
				pathSecondaire+=parameters.getParameter("pathplus");
			}
			
			if(sensNavigation.equals("suivant")){
				navigationSuivant(ctx, impl, dm, em, elm, collectivite, budget, numPage, pairBA, pathSecondaire, user);	
			} else if(sensNavigation.equals("precedent")){
				navigationPrecedent(ctx, impl, dm, em, elm, collectivite, budget, numPage, pairBA, pathSecondaire, user);
			} else if(sensNavigation.equals("premiere")){
				navigationFirst(ctx, impl, dm, em, elm, collectivite, budget, numPage, pairBA, pathSecondaire, user);
			} else if(sensNavigation.equals("derniere")){
				navigationLast(ctx, impl, dm, em, elm, collectivite, budget, numPage, pairBA, pathSecondaire, user);
			} else {
				ctx.setPath((ctx.getPath()==null?"":ctx.getPath())+pathSecondaire);
			}
		} catch (Exception e) {
			if(e instanceof UnresolvedException){
				throw (UnresolvedException)e;
			} else {
				logger.debug("Erreur", e);
				throw new UnresolvedException("treatNavigation(CustomLinkParameters parameters,NavigationContext ctx)");
			}
		}
	}
	
	private void treatAccueil(CustomLinkParameters parameters,NavigationContext ctx, XemeliosUser user) throws UnresolvedException {
		try{
			logger.debug("in treatNavigation(CustomLinkParameters parameters,NavigationContext ctx)");
			
			String budgetBA = parameters.getParameter("BudgetBA");
			String siretBA = parameters.getParameter("SiretBA");
				
			ctx.setDocId(parameters.getParameters().get("docId"));
			ctx.setEtatId(parameters.getParameters().get("etatId"));
			ctx.setElementId(parameters.getParameters().get("elementId"));
			ctx.setBudget(parameters.getSrcBudget());
			ctx.setCollectivite(parameters.getSrcCollectivite());
			
			if(parameters.getParameter("sp1") != null){
				ctx.setSp1(parameters.getParameter("sp1"));
			}
			if(parameters.getParameter("sp2") != null){
				ctx.setSp2(parameters.getParameter("sp2"));
			}
			if(parameters.getParameter("sp3") != null){
				ctx.setSp3(parameters.getParameter("sp3"));
			}
			if(parameters.getParameter("path") != null){
				ctx.setPath(parameters.getParameter("path")+getPathBudgetAnnexe(budgetBA,siretBA));
			}
		} catch (Exception e) {
			if(e instanceof UnresolvedException){
				throw (UnresolvedException)e;
			} else {
				logger.debug("Erreur", e);
				throw new UnresolvedException("treatNavigation(CustomLinkParameters parameters,NavigationContext ctx)");
			}
		}
	}
	
	private void navigationSuivant(NavigationContext ctx, DataImpl impl, DocumentModel dm, EtatModel em, ElementModel elm, Pair collectivite, Pair budget, int numPage, Pair pairBA, String pathSecondaire, XemeliosUser user) throws Exception{
		logger.debug("in navigationSuivant(NavigationContext ctx, DataImpl impl, DocumentModel dm, EtatModel em, ElementModel elm, Pair collectivite, Pair budget, int numPage, Pair pairBA, XemeliosUser user)");
		XPath xp = XPathFactory.newInstance().newXPath();
		xp.setNamespaceContext(dm.getNamespaces());
		
		ArrayList<String> docNextPage = new ArrayList<String>();
		boolean nextPageNotFound = false;
		ArrayList<String> docNextPageNotFound = new ArrayList<String>();
		
		for(int deltaPageError = 1;deltaPageError < 6;deltaPageError++){
			int numPageToSwitch = numPage+deltaPageError;
			
logger.debug("impl.getDocumentListFromXPath("+elm+", "+collectivite+", "+budget+", "+ctx.getSp1()+", "+ctx.getSp2()+", "+ctx.getSp3()+", "+"/n:"+dm.getBalise()+"/n:"+em.getBalise()+"/n:"+elm.getBalise()+"[n:Pied/@NumPage="+(numPage+deltaPageError)+"]"+pathSecondaire+", "+user+")");

			docNextPage = impl.getDocumentListFromXPath(elm, collectivite.key, budget.key, ctx.getSp1(), ctx.getSp2(), ctx.getSp3(), "/n:"+dm.getBalise()+"/n:"+em.getBalise()+"/n:"+elm.getBalise()+"[n:Pied/@NumPage="+(numPage+deltaPageError)+"]"+pathSecondaire, user);
			if(deltaPageError==5) docNextPageNotFound = impl.getDocumentListFromXPath(elm, collectivite.key, budget.key, ctx.getSp1(), ctx.getSp2(), ctx.getSp3(), "/n:"+dm.getBalise()+"/n:"+em.getBalise()+"/n:"+elm.getBalise()+"[n:Pied/@NumPage="+numPage+"]"+pathSecondaire, user);
			
			if(docNextPage!=null && docNextPage.size() > 0){
				nextPageNotFound=true;
				ctx.setPath("[n:Pied/@NumPage="+numPageToSwitch+"]"+pathSecondaire);
				break;
			}
			docNextPage.clear();
		}
		
		if(!nextPageNotFound){
			Document docNextPageDom = impl.getDocumentAsDom(em, collectivite, budget, docNextPageNotFound.get(0), user);
			logger.debug("docNextPageDom.getDocumentElement()="+docNextPageDom.getDocumentElement());
			String isLastPageEtat = (String) xp.evaluate("//n:"+elm.getBalise()+"[@added:isLastPage]",docNextPageDom.getDocumentElement(), XPathConstants.STRING);
			String nextEtat = null;
			String numNextPage = null;
			if(isLastPageEtat!=null){
				nextEtat = (String) xp.evaluate("//n:"+elm.getBalise()+"/@added:NextEtat",docNextPageDom.getDocumentElement(), XPathConstants.STRING);
				numNextPage = (String) xp.evaluate("//n:LigneSommaire[@Code='"+nextEtat+"']/@FirstPage",docNextPageDom.getDocumentElement(), XPathConstants.STRING);
			}
			//logger.debug("isLastPageEtat="+isLastPageEtat+" | nextEtat="+nextEtat+" | numNextPage="+numNextPage);
			if(nextEtat!=null && nextEtat.length() > 0){
				ctx.setEtatId(nextEtat);
				ctx.setElementId("Page"+nextEtat);
				ctx.setPath("[n:Pied/@NumPage="+numNextPage+"]"+pathSecondaire);
			}
		} 
	}
	
	private void navigationPrecedent(NavigationContext ctx, DataImpl impl, DocumentModel dm, EtatModel em, ElementModel elm, Pair collectivite, Pair budget, int numPage, Pair pairBA, String pathSecondaire, XemeliosUser user) throws Exception{
		logger.debug("in navigationPrecedent() !");
		XPath xp = XPathFactory.newInstance().newXPath();
		xp.setNamespaceContext(dm.getNamespaces());

		ArrayList<String> docPreviousPage = new ArrayList<String>();
		boolean previousPageNotFound = false;
		ArrayList<String> docPreviousPageNotFound = new ArrayList<String>();
		
		for(int deltaPageError = 1;deltaPageError < 6;deltaPageError++){
			docPreviousPage = impl.getDocumentListFromXPath(elm, collectivite.key, budget.key, ctx.getSp1(), ctx.getSp2(), ctx.getSp3(), "/n:"+dm.getBalise()+"/n:"+em.getBalise()+"/n:"+elm.getBalise()+"[n:Pied/@NumPage="+(numPage-deltaPageError)+"]"+pathSecondaire, user);
			if(deltaPageError==5) docPreviousPageNotFound = impl.getDocumentListFromXPath(elm, collectivite.key, budget.key, ctx.getSp1(), ctx.getSp2(), ctx.getSp3(), "/n:"+dm.getBalise()+"/n:"+em.getBalise()+"/n:"+elm.getBalise()+"[n:Pied/@NumPage="+numPage+"]"+pathSecondaire, user);
			
			if(docPreviousPage!=null && docPreviousPage.size() > 0){
				previousPageNotFound=true;
				ctx.setPath("[n:Pied/@NumPage="+(numPage-deltaPageError)+"]"+pathSecondaire);
				/*if(getPathBudgetAnnexe(pairBA.libelle, pairBA.key) != null && getPathBudgetAnnexe(pairBA.libelle, pairBA.key).length() > 0){
					ctx.setPath((ctx.getPath()!=null?ctx.getPath():"")+getPathBudgetAnnexe(pairBA.libelle, pairBA.key));
				}
				if(parameters.getParameter("pathplus") != null){
					ctx.setPath((ctx.getPath()!=null?ctx.getPath():"")+parameters.getParameter("pathplus"));
				}*/
				break;
			}
			docPreviousPage.clear();
		}
		
		if(!previousPageNotFound){
			Document docPreviousPageDom = impl.getDocumentAsDom(em, collectivite, budget, docPreviousPageNotFound.get(0), user);
			
			String previousEtat = (String) xp.evaluate("//n:"+elm.getBalise()+"[@added:PreviousEtat]/@added:PreviousEtat",docPreviousPageDom.getDocumentElement(), XPathConstants.STRING);
			String numPreviousPage = null;
			if(previousEtat!=null){
				//nextEtat = (String) xp.evaluate("//n:"+elm.getBalise()+"/@added:NextEtat",docPreviousPageDom.getDocumentElement(), XPathConstants.STRING);
				numPreviousPage = (String) xp.evaluate("//n:LigneSommaire[@Code='"+previousEtat+"']/@LastPage",docPreviousPageDom.getDocumentElement(), XPathConstants.STRING);
			}
			logger.debug("previousEtat="+previousEtat+" | numPreviousPage="+numPreviousPage);
			if(previousEtat!=null && previousEtat.length() > 0){
				ctx.setEtatId(previousEtat);
				ctx.setElementId("Page"+previousEtat);
				ctx.setPath("[n:Pied/@NumPage="+numPreviousPage+"]"+pathSecondaire);
				/*if(getPathBudgetAnnexe(pairBA.libelle, pairBA.key) != null && getPathBudgetAnnexe(pairBA.libelle, pairBA.key).length() > 0){
					ctx.setPath((ctx.getPath()!=null?ctx.getPath():"")+getPathBudgetAnnexe(pairBA.libelle, pairBA.key));
				}
				if(parameters.getParameter("pathplus") != null){
					ctx.setPath((ctx.getPath()!=null?ctx.getPath():"")+parameters.getParameter("pathplus"));
				}*/
			}
		} 
	}
	
	private void navigationFirst(NavigationContext ctx, DataImpl impl, DocumentModel dm, EtatModel em, ElementModel elm, Pair collectivite, Pair budget, int numPage, Pair pairBA, String pathSecondaire, XemeliosUser user) throws Exception{
		logger.debug("in navigationFirst() !");
		XPath xp = XPathFactory.newInstance().newXPath();
		xp.setNamespaceContext(dm.getNamespaces());
		
		ArrayList<String> docThisPage = impl.getDocumentListFromXPath(elm, collectivite.key, budget.key, ctx.getSp1(), ctx.getSp2(), ctx.getSp3(), "/n:"+dm.getBalise()+"/n:"+em.getBalise()+"/n:"+elm.getBalise()+"[n:Pied/@NumPage="+numPage+"]"+pathSecondaire, user);
				
		if(docThisPage!=null && docThisPage.size() > 0){
			Document docThisPageDom = impl.getDocumentAsDom(em, collectivite, budget, docThisPage.get(0), user);

			if(!isEtatSpecial(em.getBalise())){
				//  <FirstPageCG Etat="GB_PrevisionRealisationBudgetaire" V="7"/>
				String firstEtat = (String) xp.evaluate("//n:FirstPageCG/@Etat",docThisPageDom.getDocumentElement(), XPathConstants.STRING);
				String numFirstPage = (String) xp.evaluate("//n:FirstPageCG/@V",docThisPageDom.getDocumentElement(), XPathConstants.STRING);
				
				if(firstEtat!=null && firstEtat.length() > 0){
					ctx.setEtatId(firstEtat);
					ctx.setElementId("Page"+firstEtat);
					ctx.setPath("[n:Pied/@NumPage="+numFirstPage+"]"+pathSecondaire);
					/*if(getPathBudgetAnnexe(pairBA.libelle, pairBA.key) != null && getPathBudgetAnnexe(pairBA.libelle, pairBA.key).length() > 0){
						ctx.setPath((ctx.getPath()!=null?ctx.getPath():"")+getPathBudgetAnnexe(pairBA.libelle, pairBA.key));
					}
					if(parameters.getParameter("pathplus") != null){
						ctx.setPath((ctx.getPath()!=null?ctx.getPath():"")+parameters.getParameter("pathplus"));
					}*/
				}
			} else { // go to first page
				ctx.setPath("[n:Pied/@NumPage=1]"+pathSecondaire);
				/*if(getPathBudgetAnnexe(pairBA.libelle, pairBA.key) != null && getPathBudgetAnnexe(pairBA.libelle, pairBA.key).length() > 0){
					ctx.setPath((ctx.getPath()!=null?ctx.getPath():"")+getPathBudgetAnnexe(pairBA.libelle, pairBA.key));
				}
				if(parameters.getParameter("pathplus") != null){
					ctx.setPath((ctx.getPath()!=null?ctx.getPath():"")+parameters.getParameter("pathplus"));
				}*/
			}
		}
	}
	
	private void navigationLast(NavigationContext ctx, DataImpl impl, DocumentModel dm, EtatModel em, ElementModel elm, Pair collectivite, Pair budget, int numPage, Pair pairBA, String pathSecondaire, XemeliosUser user) throws Exception{
		logger.debug("in navigationLast() !");
		XPath xp = XPathFactory.newInstance().newXPath();
		xp.setNamespaceContext(dm.getNamespaces());
		
		ArrayList<String> docThisPage = impl.getDocumentListFromXPath(elm, collectivite.key, budget.key, ctx.getSp1(), ctx.getSp2(), ctx.getSp3(), "/n:"+dm.getBalise()+"/n:"+em.getBalise()+"/n:"+elm.getBalise()+"[n:Pied/@NumPage="+numPage+"]"+pathSecondaire, user);
				
		if(docThisPage!=null && docThisPage.size() > 0){
			Document docThisPageDom = impl.getDocumentAsDom(em, collectivite, budget, docThisPage.get(0), user);

			if(!isEtatSpecial(em.getBalise())){
				//  <LastPageCG Etat="EtatRestesRecouvrer" V="124"/>
				String lastEtat = (String) xp.evaluate("//n:LastPageCG/@Etat",docThisPageDom.getDocumentElement(), XPathConstants.STRING);
				String numLastPage = (String) xp.evaluate("//n:LastPageCG/@V",docThisPageDom.getDocumentElement(), XPathConstants.STRING);
				
				if(lastEtat!=null && lastEtat.length() > 0){
					ctx.setEtatId(lastEtat);
					ctx.setElementId("Page"+lastEtat);
					ctx.setPath("[n:Pied/@NumPage="+numLastPage+"]"+pathSecondaire);
					/*if(getPathBudgetAnnexe(pairBA.libelle, pairBA.key) != null && getPathBudgetAnnexe(pairBA.libelle, pairBA.key).length() > 0){
						ctx.setPath((ctx.getPath()!=null?ctx.getPath():"")+getPathBudgetAnnexe(pairBA.libelle, pairBA.key));
					}
					if(parameters.getParameter("pathplus") != null){
						ctx.setPath((ctx.getPath()!=null?ctx.getPath():"")+parameters.getParameter("pathplus"));
					}*/
				}
			} else { // go to first page
				String etat = em.getBalise();
				String codeEdition = (String) xp.evaluate("//n:Page"+etat+"/@CodeEdition",docThisPageDom.getDocumentElement(), XPathConstants.STRING);
				if(etat.equalsIgnoreCase("Solde")){
					etat="Solde-"+codeEdition;
				}
				String numLastPage = (String) xp.evaluate("//n:LigneSommairePlus[@Code='"+etat+"']/@LastPage",docThisPageDom.getDocumentElement(), XPathConstants.STRING);
				logger.debug("lastpage="+numLastPage+" ** codeEdition="+etat);
				ctx.setPath("[n:Pied/@NumPage="+numLastPage+"]"+pathSecondaire);
				/*if(getPathBudgetAnnexe(pairBA.libelle, pairBA.key) != null && getPathBudgetAnnexe(pairBA.libelle, pairBA.key).length() > 0){
					ctx.setPath((ctx.getPath()!=null?ctx.getPath():"")+getPathBudgetAnnexe(pairBA.libelle, pairBA.key));
				}
				if(parameters.getParameter("pathplus") != null){
					ctx.setPath((ctx.getPath()!=null?ctx.getPath():"")+parameters.getParameter("pathplus"));
				}*/
			}
		}
	}
	
	private boolean isEtatSpecial(String balise){		
		if(balise.equals("Solde") || balise.equals("DeveloppementSoldes") || balise.equals("FichesBudgetaires") || balise.equals("LivreAuxiliaire")) return true;
		return false;
	}
	
	/**
	 * @return the additionalsParameters
	 */
	public Properties getXslParameters() {
		return xslParameters;
	}

	/**
	 * @param additionalsParameters the additionalsParameters to set
	 */
	public void setXslParameters(Properties additionalsParameters) {
		this.xslParameters = additionalsParameters;
	}

	private void debug(Document doc){
		try {
			Transformer t = net.sf.saxon.TransformerFactoryImpl.newInstance().newTransformer();
			t.transform(new DOMSource(doc), new StreamResult(System.out));
		} catch (TransformerException e) {
			e.printStackTrace();
		}
	}

}
