fr.crnan.videso3d.databases.aip.AIP.java Source code

Java tutorial

Introduction

Here is the source code for fr.crnan.videso3d.databases.aip.AIP.java

Source

/*
 * This file is part of ViDESO.
 * ViDESO is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ViDESO 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ViDESO.  If not, see <http://www.gnu.org/licenses/>.
 */

package fr.crnan.videso3d.databases.aip;

import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.filter.AbstractFilter;
import org.jdom2.filter.Filter;
import org.jdom2.input.SAXBuilder;

import fr.crnan.videso3d.Couple;
import fr.crnan.videso3d.DatasManager;
import fr.crnan.videso3d.FileParser;
import fr.crnan.videso3d.databases.DatabaseManager;
import fr.crnan.videso3d.graphics.Route;

/**
 * Lecteur des exports en xml du SIA
 * @author Adrien Vidal
 * @version 0.3.5
 */
public class AIP extends FileParser {

    private final Integer numberFiles = 23;

    /**
     * Le nom de la base de donnes.
     */
    private String name;

    /**
     * Le chemin du fichier xml utilis
     */
    private String fileName;

    /**
     * Connection  la base de donnes
     */
    private Connection conn;

    /**
     * Le <code>document</code> construit  partir du fichier xml.
     */
    private Document document = null;

    private List<Couple<Integer, String>> TSAs;
    private List<Couple<Integer, String>> SIVs;
    private List<Couple<Integer, String>> CTRs;
    private List<Couple<Integer, String>> TMAs;
    private List<Couple<Integer, String>> Ps;
    private List<Couple<Integer, String>> Rs;
    private List<Couple<Integer, String>> Ds;
    private List<Couple<Integer, String>> FIRs;
    private List<Couple<Integer, String>> UIRs;
    private List<Couple<Integer, String>> LTAs;
    private List<Couple<Integer, String>> UTAs;
    private List<Couple<Integer, String>> CTAs;
    private List<Couple<Integer, String>> OCAs;
    private List<Couple<Integer, String>> PRNs;
    private List<Couple<Integer, String>> CTLs;
    private List<Couple<Integer, String>> Pjes;
    private List<Couple<Integer, String>> Aers;
    private List<Couple<Integer, String>> Vols;
    private List<Couple<Integer, String>> Bals;
    private List<Couple<Integer, String>> TrPlas;

    public final static int Partie = 0, TSA = 1, SIV = 2, CTR = 3, TMA = 4, R = 5, D = 6, FIR = 7, UIR = 8, LTA = 9,
            UTA = 10, CTA = 11, CTL = 12, Pje = 13, Aer = 14, Vol = 15, Bal = 16, TrPla = 17, OCA = 18, P = 19,
            PRN = 20, AWY = 21, PDR = 22, TAC = 23, DMEATT = 30, L = 31, NDB = 32, PNP = 33, TACAN = 34, VFR = 35,
            VOR = 36, VORDME = 37, VORTAC = 38, WPT = 39, AERODROME = 40, ALTI = 41, PRIVE = 42;

    public AIP(String path) {
        super(path);
        this.fileName = path;
        //construction du document  partir du fichier xml
        SAXBuilder sxb = new SAXBuilder();
        try {
            document = sxb.build(new File(path));
        } catch (JDOMException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public AIP() {
        this.TSAs = new ArrayList<Couple<Integer, String>>();
        this.SIVs = new ArrayList<Couple<Integer, String>>();
        this.CTRs = new ArrayList<Couple<Integer, String>>();
        this.TMAs = new ArrayList<Couple<Integer, String>>();
        this.Ps = new ArrayList<Couple<Integer, String>>();
        this.Rs = new ArrayList<Couple<Integer, String>>();
        this.Ds = new ArrayList<Couple<Integer, String>>();
        this.FIRs = new ArrayList<Couple<Integer, String>>();
        this.UIRs = new ArrayList<Couple<Integer, String>>();
        this.LTAs = new ArrayList<Couple<Integer, String>>();
        this.UTAs = new ArrayList<Couple<Integer, String>>();
        this.CTAs = new ArrayList<Couple<Integer, String>>();
        this.OCAs = new ArrayList<Couple<Integer, String>>();
        this.PRNs = new ArrayList<Couple<Integer, String>>();
        this.CTLs = new ArrayList<Couple<Integer, String>>();
        this.Pjes = new ArrayList<Couple<Integer, String>>();
        this.Aers = new ArrayList<Couple<Integer, String>>();
        this.Vols = new ArrayList<Couple<Integer, String>>();
        this.Bals = new ArrayList<Couple<Integer, String>>();
        this.TrPlas = new ArrayList<Couple<Integer, String>>();
        final SAXBuilder sxb = new SAXBuilder();
        try {
            this.name = DatabaseManager.getCurrentName(DatasManager.Type.AIP);
            //on rcupre le chemin d'accs au fichier xml  parser
            Statement st = DatabaseManager.getCurrent(DatasManager.Type.Databases);
            ResultSet rs;
            rs = st.executeQuery("select * from clefs where name='path' and type='"
                    + DatabaseManager.getCurrentName(DatasManager.Type.AIP) + "'");
            if (rs.next()) {
                this.fileName = rs.getString(4);
                //Construction du document dans un autre thread afin de ne pas bloquer l'initialisation
                //TODO trouver une autre mthode car cela empche le chargement d'un projet
                //            new Thread(){
                //               @Override
                //               public void run(){
                try {
                    document = sxb.build(new File(name + "_files", fileName));
                } catch (JDOMException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                //               }
                //            }.start();
            }
            //TODO prendre en compte la possibilit qu'il n'y ait pas de bdd AIP
            Statement aipDB = DatabaseManager.getCurrentAIP();
            if (aipDB != null) {
                //on rcupre tous les volumes
                ResultSet rSet = aipDB.executeQuery("select * from volumes");
                while (rSet.next()) {
                    Couple<Integer, String> id_name = new Couple<Integer, String>(rSet.getInt(2),
                            rSet.getString(4));
                    String type = rSet.getString(3);
                    getZones(string2type(type)).add(id_name);
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * Determine if the file is a AIP file (XML containing AIP datas)
     * TODO Do it better
     * @param file
     * @return <code>true</code> if it is an AIP xml database
     */
    public static boolean isAIPFile(File file) {
        SAXBuilder sxb = new SAXBuilder();
        boolean isAIP = false;
        try {
            isAIP = sxb.build(file).getRootElement().getName().equals("SiaExport");
        } catch (JDOMException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return isAIP;
    }

    @Override
    public Integer doInBackground() {
        try {
            //rcupration du nom de la base  crer
            this.createName();
            if (!DatabaseManager.databaseExists(DatasManager.Type.AIP, this.name)) {
                //cration de la connection  la base de donnes
                this.conn = DatabaseManager.selectDB(DatasManager.Type.AIP, this.name);
                this.conn.setAutoCommit(false); //fixes performance issue
                //cration de la structure de la base de donnes
                DatabaseManager.createAIP(this.name, path);
                //parsing des fichiers et stockage en base
                this.getFromFiles();
                this.conn.commit();
                this.setProgress(this.numberFiles());
            } else {
                DatabaseManager.selectDatabase(this.name, DatasManager.Type.AIP);
            }
        } catch (SQLException e) {
            e.printStackTrace();
            this.cancel(true);
        }
        return this.numberFiles();
    }

    /**
     * 
     * @return L'lment Situation, qui contient tous les objets qui nous intressent.
     */
    public Element getDocumentRoot() {
        return document.getRootElement().getChild("Situation");
    }

    /**
     * Cre le nom de la base : AIP_date d'entre en vigueur
     */
    private void createName() {
        this.name = "AIP_" + document.getRootElement().getChild("Situation").getAttributeValue("effDate");
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    protected void getFromFiles() throws SQLException {
        int progress = 0;
        Element racineVolumes = document.getRootElement().getChild("Situation").getChild("VolumeS");
        this.TSAs = new ArrayList<Couple<Integer, String>>();
        this.SIVs = new ArrayList<Couple<Integer, String>>();
        this.CTRs = new ArrayList<Couple<Integer, String>>();
        this.TMAs = new ArrayList<Couple<Integer, String>>();
        this.Ps = new ArrayList<Couple<Integer, String>>();
        this.Rs = new ArrayList<Couple<Integer, String>>();
        this.Ds = new ArrayList<Couple<Integer, String>>();
        this.FIRs = new ArrayList<Couple<Integer, String>>();
        this.UIRs = new ArrayList<Couple<Integer, String>>();
        this.LTAs = new ArrayList<Couple<Integer, String>>();
        this.UTAs = new ArrayList<Couple<Integer, String>>();
        this.CTAs = new ArrayList<Couple<Integer, String>>();
        this.OCAs = new ArrayList<Couple<Integer, String>>();
        this.PRNs = new ArrayList<Couple<Integer, String>>();
        this.CTLs = new ArrayList<Couple<Integer, String>>();
        this.Pjes = new ArrayList<Couple<Integer, String>>();
        this.Aers = new ArrayList<Couple<Integer, String>>();
        this.Vols = new ArrayList<Couple<Integer, String>>();
        this.Bals = new ArrayList<Couple<Integer, String>>();
        this.TrPlas = new ArrayList<Couple<Integer, String>>();
        this.setFile("Aerodromes");
        this.setProgress(progress);
        this.getAerodromes();
        this.setFile("TSA");
        this.setProgress(progress++);
        this.getTSAs(racineVolumes);
        this.setFile("SIV");
        this.setProgress(progress++);
        this.getZones(racineVolumes, "SIV");
        this.setFile("CTR");
        this.setProgress(progress++);
        this.getZones(racineVolumes, "CTR");
        this.setFile("TMA");
        this.setProgress(progress++);
        this.getZones(racineVolumes, "TMA");
        this.setFile("P");
        this.setProgress(progress++);
        this.getZones(racineVolumes, "P");
        this.setFile("R");
        this.setProgress(progress++);
        this.getZones(racineVolumes, "R");
        this.setFile("D");
        this.setProgress(progress++);
        this.getZones(racineVolumes, "D");
        this.setFile("FIR");
        this.setProgress(progress++);
        this.getZones(racineVolumes, "FIR");
        this.setFile("UIR");
        this.setProgress(progress++);
        this.getZones(racineVolumes, "UIR");
        this.setFile("LTA");
        this.setProgress(progress++);
        this.getZones(racineVolumes, "LTA");
        this.setFile("UTA");
        this.setProgress(progress++);
        this.getZones(racineVolumes, "UTA");
        this.setFile("CTA");
        this.setProgress(progress++);
        this.getZones(racineVolumes, "CTA");
        this.setFile("OCA");
        this.setProgress(progress++);
        this.getZones(racineVolumes, "OCA");
        this.setFile("PRN");
        this.setProgress(progress++);
        this.getZones(racineVolumes, "PRN");
        this.setFile("CTL");
        this.setProgress(progress++);
        this.getZones(racineVolumes, "CTL");
        this.setFile("Parachutages");
        this.setProgress(progress++);
        this.getZones(racineVolumes, "Pje");
        this.setFile("Aer");
        this.setProgress(progress++);
        this.getZones(racineVolumes, "Aer");
        this.setFile("Voltige");
        this.setProgress(progress++);
        this.getZones(racineVolumes, "Vol");
        this.setFile("Ballons");
        this.setProgress(progress++);
        this.getZones(racineVolumes, "Bal");
        this.setFile("Treuils planeurs");
        this.setProgress(progress++);
        this.getZones(racineVolumes, "TrPla");
        this.setFile("Routes");
        this.setProgress(progress++);
        this.getRoutes();
        this.setFile("Navigation Fix");
        this.setProgress(progress++);
        this.getBalises();
        this.setFile("Frquences");
        this.setProgress(progress++);
        this.getFrequences();
        this.setProgress(progress++);
    }

    private void getFrequences() {
        try {
            Element racineFrequenceS = getDocumentRoot().getChild("FrequenceS");
            List<Element> frequences = racineFrequenceS.getChildren();
            for (Element freq : frequences) {
                Element secteur = freq.getChild("SecteurSituation");
                if (secteur != null) {
                    String frequence = freq.getChildText("Frequence");
                    if (frequence.startsWith("1"))
                        insertFrequence(secteur.getText(), frequence);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void insertFrequence(String secteur, String frequence) {
        String[] secteurs = secteur.split("/");
        for (String sect : secteurs) {
            PreparedStatement ps;
            try {
                ps = this.conn.prepareStatement("insert into frequences (nom, frequence) VALUES (?, ?)");

                ps.setString(1, sect);
                ps.setString(2, frequence);
                ps.executeUpdate();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    private void getAerodromes() throws SQLException {
        try {
            Element racineAds = getDocumentRoot().getChild("AdS");
            List<Element> ads = racineAds.getChildren();
            for (Element ad : ads) {
                if (!ad.getChildText("AdStatut").equals("OFF"))
                    insertAerodrome(ad);
            }
            Element racineRwys = getDocumentRoot().getChild("RwyS");
            List<Element> rwys = racineRwys.getChildren();
            for (Element rwy : rwys) {
                insertRunway(rwy);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void insertAerodrome(Element ad) throws SQLException {
        int pk = Integer.parseInt(ad.getAttributeValue("pk"));
        String code = ad.getAttributeValue("lk").replaceAll("\\p{Punct}", "").toUpperCase(Locale.ENGLISH);
        String nom = ad.getChildText("AdNomComplet");
        int type = code.matches("[A-Z]{4}") ? 0 : (code.matches("LF[0-9]{2}") ? 2 : 1);
        double latRef = Double.parseDouble(ad.getChildText("ArpLat"));
        double lonRef = Double.parseDouble(ad.getChildText("ArpLong"));
        PreparedStatement ps = this.conn.prepareStatement(
                "insert into aerodromes (pk, code, nom, type, latRef, lonRef) VALUES (?, ?, ?, ?, ?, ?)");
        ps.setInt(1, pk);
        ps.setString(2, code);
        ps.setString(3, nom);
        ps.setInt(4, type);
        ps.setDouble(5, latRef);
        ps.setDouble(6, lonRef);
        ps.executeUpdate();
    }

    private void insertRunway(Element rwy) throws SQLException {
        int pk = Integer.parseInt(rwy.getAttributeValue("pk"));
        int pkAerodrome = Integer.parseInt(rwy.getChild("Ad").getAttributeValue("pk"));
        String rwyName = rwy.getChildText("Rwy");
        int orientation = getRunwayOrientation(rwyName);
        String largeurString = rwy.getChildText("Largeur");
        double largeur = -1;
        if (largeurString != null)
            largeur = Double.parseDouble(largeurString);
        String longueurString = rwy.getChildText("Longueur");
        double longueur = -1;
        if (longueurString != null)
            longueur = Double.parseDouble(longueurString);

        PreparedStatement ps = this.conn.prepareStatement(
                "insert into runways (pk, pk_ad, nom, orientation, longueur, largeur) VALUES (?, ?, ?, ?, ?, ?)");
        ps.setInt(1, pk);
        ps.setInt(2, pkAerodrome);
        ps.setString(3, rwyName);
        ps.setInt(4, orientation);
        ps.setDouble(5, longueur);
        ps.setDouble(6, largeur);
        ps.executeUpdate();

        String latThr1 = rwy.getChildText("LatThr1");
        String lonThr1 = rwy.getChildText("LongThr1");
        String latThr2 = rwy.getChildText("LatThr2");
        String lonThr2 = rwy.getChildText("LongThr2");

        if (latThr1 != null && latThr2 != null) {
            PreparedStatement ps2 = this.conn
                    .prepareStatement("update runways set lat1=?, lon1=?,lat2=?,lon2=? where pk=?");
            ps2.setDouble(1, Double.parseDouble(latThr1));
            ps2.setDouble(2, Double.parseDouble(lonThr1));
            ps2.setDouble(3, Double.parseDouble(latThr2));
            ps2.setDouble(4, Double.parseDouble(lonThr2));
            ps2.setInt(5, pk);
            ps2.executeUpdate();
        }

    }

    private int getRunwayOrientation(String rwyName) {
        String firstQFU = rwyName.split("/")[0];
        if (firstQFU.startsWith("NW")) {
            return 45;
        }
        if (firstQFU.endsWith("R") || firstQFU.endsWith("L") || firstQFU.endsWith("C")) {
            firstQFU = firstQFU.substring(0, firstQFU.length() - 1);
        }
        if (firstQFU.equals("XX")) {
            return -1;
        }
        return Integer.parseInt(firstQFU);
    }

    private void getBalises() throws SQLException {
        Element racineNavFix = document.getRootElement().getChild("Situation").getChild("NavFixS");
        List<Element> navFix = racineNavFix.getChildren();
        for (Element fix : navFix) {
            insertNavFix(fix);
        }
    }

    private void insertNavFix(Element navFix) throws SQLException {
        String pk = navFix.getAttributeValue("pk");
        String type = navFix.getChildText("NavType");
        String name = navFix.getChildText("Ident");
        String territoireID = navFix.getChild("Territoire").getAttributeValue("pk");
        double latitude = Double.parseDouble(navFix.getChildText("Latitude"));
        double longitude = Double.parseDouble(navFix.getChildText("Longitude"));
        if (!territoireID.equals("100")) {
            name += " - " + getTerritoireName(territoireID);
        }

        double freq = 0;
        if (!type.equals("VFR") && !type.equals("WPT") && !type.equals("PNP")) {
            List<Element> elts = findElementsByChildId(
                    document.getRootElement().getChild("Situation").getChild("RadioNavS"), "NavFix", pk);
            if (elts.size() > 0) {
                freq = Double.parseDouble(elts.get(0).getChildText("Frequence"));
            }
        }

        PreparedStatement ps = this.conn.prepareStatement(
                "insert into NavFix (pk, type, nom, lat, lon, frequence) VALUES (?, ?, ?, ?, ?, ?)");
        ps.setInt(1, Integer.parseInt(pk));
        ps.setString(2, type);
        ps.setString(3, name);
        ps.setDouble(4, latitude);
        ps.setDouble(5, longitude);
        ps.setDouble(6, freq);
        ps.executeUpdate();
    }

    private void getRoutes() throws SQLException {
        Element racineRoutes = document.getRootElement().getChild("Situation").getChild("RouteS");
        List<Element> routes = racineRoutes.getChildren();
        for (Element route : routes) {
            insertRoute(route);
        }
    }

    private void insertRoute(Element route) throws SQLException {
        String pkRoute = route.getAttributeValue("pk");
        int routeID = Integer.parseInt(pkRoute);
        String routeName = route.getChildText("Prefixe") + " " + route.getChildText("Numero");
        String territoireID = route.getChild("Territoire").getAttributeValue("pk");
        if (!territoireID.equals("100")) {
            routeName += " - " + getTerritoireName(territoireID);
        }
        PreparedStatement ps;
        int navFixExtremite = Integer.parseInt(route.getChild("Origine").getAttributeValue("pk"));
        ps = this.conn.prepareStatement("insert into routes (pk,type,nom, navFixExtremite) VALUES (?, ?, ?, ?)");
        ps.setInt(1, routeID);
        ps.setString(2, route.getChildText("RouteType"));
        ps.setString(3, routeName);
        ps.setInt(4, navFixExtremite);
        ps.executeUpdate();
        Element racineSegments = document.getRootElement().getChild("Situation").getChild("SegmentS");
        List<Element> segments = findElementsByChildId(racineSegments, "Route", pkRoute);
        for (Element segment : segments) {
            int segmentID = Integer.parseInt(segment.getAttributeValue("pk"));
            int sequence = Integer.parseInt(segment.getChildText("Sequence"));
            navFixExtremite = Integer.parseInt(segment.getChild("NavFixExtremite").getAttributeValue("pk"));
            ps = this.conn.prepareStatement(
                    "insert into segments (pk, pkRoute, sequence, navFixExtremite) VALUES (?, ?, ?, ?)");
            ps.setInt(1, segmentID);
            ps.setInt(2, routeID);
            ps.setInt(3, sequence);
            ps.setInt(4, navFixExtremite);
            ps.executeUpdate();
            //Insertion des centres traverss par la route : pour chaque segment, on ajoute le centre  la liste des centres traverss
            String nomACC = segment.getChildText("Acc");
            if (nomACC != null) {
                if (nomACC.contains(" ")) {
                    String[] nomsACCs = nomACC.split(" ");
                    insertACCs(nomsACCs, pkRoute);
                } else if (nomACC.contains("#")) {
                    String[] nomsACCs = nomACC.split("#");
                    insertACCs(nomsACCs, pkRoute);
                } else {
                    insertACC(nomACC, pkRoute);

                }
            }
        }
    }

    private void insertACCs(String[] nomsACCs, String pkRoute) throws SQLException {
        for (String nom : nomsACCs) {
            insertACC(nom, pkRoute);
        }
    }

    private void insertACC(String nomACC, String pkRoute) throws SQLException {
        boolean insertACC = true;
        PreparedStatement ps = this.conn.prepareStatement("select * from ACCTraverses where routes_pk = ?");
        ps.setString(1, pkRoute);
        ResultSet rs = ps.executeQuery();
        while (rs.next()) {
            if (rs.getString(2).equals(nomACC)) {
                insertACC = false;
                break;
            }
        }
        if (insertACC) {
            ps = this.conn.prepareStatement("insert into ACCTraverses (routes_pk, nomACC) VALUES (?, ?)");
            ps.setString(1, pkRoute);
            ps.setString(2, nomACC);
            ps.executeUpdate();
        }
    }

    /**
     * Cherche tous les lments Volume qui sont des TSA, et insre leur nom dans la base de donnes
     * @throws SQLException 
     */
    private void getTSAs(Element racine) throws SQLException {
        List<Element> cbaList = findVolumes(racine, "lk", "CBA");
        List<Element> tsaList = findVolumes(racine, "lk", "TSA");
        Iterator<Element> itCBA = cbaList.iterator();
        Iterator<Element> itTSA = tsaList.iterator();
        while (itCBA.hasNext()) {
            Element cba = itCBA.next();
            this.insertZone(cba, getVolumeName(cba.getAttributeValue("lk")), false, "TSA");
        }
        while (itTSA.hasNext()) {
            Element tsa = itTSA.next();
            this.insertZone(tsa, getVolumeName(tsa.getAttributeValue("lk")), false, "TSA");
        }
    }

    /**
     * 
     * @param racine
     * @param type
     * @throws SQLException 
     */
    private void getZones(Element racine, String type) throws SQLException {
        List<Element> zoneList;
        if (type.equals("P")) {
            zoneList = findVolumes(racine, "lk", "P ");
        } else {
            zoneList = findVolumes(racine, "lk", type);
        }
        Iterator<Element> it1 = zoneList.iterator();
        Iterator<Element> it2 = zoneList.iterator();
        HashSet<String> sameNames = new HashSet<String>();
        ArrayList<String> names = new ArrayList<String>();
        while (it1.hasNext()) {
            Element zone = it1.next();
            String zoneName = getVolumeName(zone.getAttributeValue("lk"));
            if (!names.contains(zoneName)) {
                names.add(zoneName);
            } else {
                sameNames.add(zoneName);
            }
        }
        while (it2.hasNext()) {
            Element zoneElement = it2.next();
            String zoneName = getVolumeName(zoneElement.getAttributeValue("lk"));
            if (sameNames.contains(zoneName)) {
                this.insertZone(zoneElement, zoneName, true, type);
            } else {
                this.insertZone(zoneElement, zoneName, false, type);
            }
        }
    }

    /**
     * Insre dans la base de donnes la zone passe en paramtre
     * @param zone Le secteur (ou zone...)  insrer dans la base.
     * @param displaySequence Boolen indiquant s'il faut afficher le numro de squence de la zone ou pas.
     * @param type
     * @throws SQLException
     */
    private void insertZone(Element zone, String name, boolean displaySequence, String type) throws SQLException {
        int zoneID = Integer.parseInt(zone.getAttributeValue("pk"));
        //on teste s'il s'agit d'une zone Pje, Aer, Vol, Bal ou TrPla en regardant si le deuxime caractre est en minuscule : si c'est le cas,
        // on recherche le nom usuel. On cherche aussi le nom usuel pour les zones P et PRN.
        if (type.length() > 1) {
            if (Character.isLowerCase(type.charAt(1)) || type.equals("PRN")) {
                String usualName = getUsualName(zone);
                if (usualName != null) {
                    name += " -- " + usualName;
                }
            }

        } else if (type.equals("P")) {
            String usualName = getUsualName(zone);
            if (usualName != null) {
                name += " -- " + usualName;
            }
        }
        if (displaySequence) {
            name += " " + zone.getChildText("Sequence");
        }
        getZones(string2type(type)).add(new Couple<Integer, String>(zoneID, name));
        PreparedStatement ps = this.conn.prepareStatement("insert into volumes (pk,type,nom) VALUES (?, ?, ?)");
        ps.setInt(1, zoneID);
        ps.setString(2, type);
        ps.setString(3, removeType(name));
        ps.executeUpdate();
    }

    /**
     * Rcupre le nom du volume en enlevant les [] et les caractres inutiles.
     */
    private String getVolumeName(String fullName) {
        String name = fullName.substring(5);
        String region = fullName.substring(1, 3);
        if (name.charAt(1) == ']') {
            name = name.substring(3);
        }
        int firstBracket = name.indexOf("[");
        if (!name.substring(firstBracket + 1, firstBracket + 3).equals(".]")) {
            name = name.replaceFirst("[\\]]", " ");
            name = name.replaceFirst("[\\[]", "");
        }
        int bracketIndex = name.indexOf(']');
        return region.equals("LF") ? name.substring(0, bracketIndex)
                : name.substring(0, bracketIndex) + " " + region;
    }

    private String getUsualName(Element zone) {
        String usualName = null;
        String partieID = zone.getChild("Partie").getAttributeValue("pk");
        Element partie = this.findElement(document.getRootElement().getChild("Situation").getChild("PartieS"),
                partieID);
        usualName = partie.getChildText("NomUsuel");
        return usualName;
    }

    /**
     * Vrifie si le nom de la zone commence par le type (CTR, TMA,...)
     * @param name Le nom  vrifier
     * @return Le nom amput du type de zone, sauf si c'est une zone P, R ou D.
     */
    private String removeType(String name) {
        int lettersToRemove = 0;
        if (name.startsWith("SIV") || name.startsWith("CTR") || name.startsWith("TMA") || name.startsWith("FIR")
                || name.startsWith("UIR") || name.startsWith("LTA") || name.startsWith("UTA")
                || name.startsWith("CTA") || name.startsWith("OCA") || name.startsWith("CTL")
                || name.startsWith("Pje") || name.startsWith("Aer") || name.startsWith("Vol")
                || name.startsWith("Bal")) {
            lettersToRemove = 4;
        }
        if (name.startsWith("TrPla"))
            lettersToRemove = 6;
        return name.substring(lettersToRemove);
    }

    @Override
    public int numberFiles() {
        return this.numberFiles;
    }

    public List<Couple<Integer, String>> getZones(int type) {
        switch (type) {
        case TSA:
            return TSAs;
        case SIV:
            return SIVs;
        case CTR:
            return CTRs;
        case TMA:
            return TMAs;
        case P:
            return Ps;
        case R:
            return Rs;
        case D:
            return Ds;
        case FIR:
            return FIRs;
        case UIR:
            return UIRs;
        case LTA:
            return LTAs;
        case UTA:
            return UTAs;
        case CTA:
            return CTAs;
        case OCA:
            return OCAs;
        case PRN:
            return PRNs;
        case CTL:
            return CTLs;
        case Pje:
            return Pjes;
        case Aer:
            return Aers;
        case Vol:
            return Vols;
        case Bal:
            return Bals;
        case TrPla:
            return TrPlas;
        }
        return null;
    }

    public static String type2String(int type) {
        switch (type) {
        case TSA:
            return "TSA";
        case SIV:
            return "SIV";
        case CTR:
            return "CTR";
        case TMA:
            return "TMA";
        case P:
            return "P";
        case R:
            return "R";
        case D:
            return "D";
        case FIR:
            return "FIR";
        case UIR:
            return "UIR";
        case LTA:
            return "LTA";
        case UTA:
            return "UTA";
        case CTA:
            return "CTA";
        case OCA:
            return "OCA";
        case PRN:
            return "PRN";
        case CTL:
            return "CTL";
        case Pje:
            return "Pje";
        case Aer:
            return "Aer";
        case Vol:
            return "Vol";
        case Bal:
            return "Bal";
        case TrPla:
            return "TrPla";
        case AWY:
            return "AWY";
        case PDR:
            return "PDR";
        case TAC:
            return "TAC";
        case DMEATT:
            return "DME-ATT";
        case L:
            return "L";
        case NDB:
            return "NDB";
        case PNP:
            return "PNP";
        case TACAN:
            return "TACAN";
        case VFR:
            return "VFR";
        case VOR:
            return "VOR";
        case VORDME:
            return "VOR-DME";
        case VORTAC:
            return "VORTAC";
        case WPT:
            return "WPT";
        case AERODROME:
            return "Aerodromes";
        case ALTI:
            return "Altisurfaces";
        case PRIVE:
            return "Terrains privs";
        default:
            return "";
        }
    }

    public static int string2type(String type) {
        if (type.equals("0")) {
            return AERODROME;
        }
        if (type.equals("1")) {
            return ALTI;
        }
        if (type.equals("2")) {
            return PRIVE;
        }
        if (type.equals("TSA")) {
            return TSA;
        }
        if (type.equals("TMA")) {
            return TMA;
        }
        if (type.equals("CTR")) {
            return CTR;
        }
        if (type.equals("SIV")) {
            return SIV;
        }
        if (type.equals("P")) {
            return P;
        }
        if (type.equals("R")) {
            return R;
        }
        if (type.equals("D")) {
            return D;
        }
        if (type.equals("FIR")) {
            return FIR;
        }
        if (type.equals("UIR")) {
            return UIR;
        }
        if (type.equals("LTA")) {
            return LTA;
        }
        if (type.equals("UTA")) {
            return UTA;
        }
        if (type.equals("CTA")) {
            return CTA;
        }
        if (type.equals("OCA")) {
            return OCA;
        }
        if (type.equals("PRN")) {
            return PRN;
        }
        if (type.equals("CTL")) {
            return CTL;
        }
        if (type.equals("Pje")) {
            return Pje;
        }
        if (type.equals("Aer")) {
            return Aer;
        }
        if (type.equals("Vol")) {
            return Vol;
        }
        if (type.equals("Bal")) {
            return Bal;
        }
        if (type.equals("TrPla")) {
            return TrPla;
        }
        if (type.equals("AWY")) {
            return AWY;
        }
        if (type.equals("PDR")) {
            return PDR;
        }
        if (type.equals("TAC")) {
            return TAC;
        }
        if (type.equals("DME-ATT")) {
            return DMEATT;
        }
        if (type.equals("L")) {
            return L;
        }
        if (type.equals("NDB")) {
            return NDB;
        }
        if (type.equals("PNP")) {
            return PNP;
        }
        if (type.equals("TACAN")) {
            return TACAN;
        }
        if (type.equals("VFR")) {
            return VFR;
        }
        if (type.equals("VOR")) {
            return VOR;
        }
        if (type.equals("VOR-DME")) {
            return VORDME;
        }
        if (type.equals("VORTAC")) {
            return VORTAC;
        }
        if (type.equals("WPT")) {
            return WPT;
        }
        if (type.equals("Arodromes")) {
            return AERODROME;
        }
        if (type.equals("Altisurfaces")) {
            return ALTI;
        }
        if (type.equals("Terrains privs")) {
            return PRIVE;
        }
        return -1;
    }

    public String RouteType2AIPType(String routeName, Route.Space type) {
        if (routeName.startsWith("T") && routeName.charAt(1) != ' ') {
            return "TAC";
        } else {
            return type.equals(Route.Space.FIR) ? "AWY" : "PDR";
        }
    }

    @Override
    public void done() {
        if (this.isCancelled()) {//si le parsing a t annul, on fait le mnage
            try {
                DatabaseManager.deleteDatabase(name, DatasManager.Type.AIP);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            firePropertyChange("done", true, false);
        } else {
            firePropertyChange("done", false, true);
        }
    }

    /**
     * Liste tous les lments dont le champ fieldParam <b>commence</b> par la chane de caractres "value", parmi les fils de l'lment racine.
     * <i>A n'utiliser que pour chercher des volumes par leur nom.</i>
     * @param root Le noeud contenant les lments parmi lesquels on effectue la recherche
     * @param fieldParam Le champ sur lequel porte la recherche
     * @param value La valeur du champ fieldParam
     * @return la liste des lments rpondant au critre.
     */
    public List<Element> findVolumes(Element root, String fieldParam, String value) {
        final String field = fieldParam;
        final String identity = value;
        Filter<Element> f = new AbstractFilter<Element>() {

            @Override
            public Element filter(Object o) {
                if (o instanceof Element) {
                    Element element = (Element) o;
                    String name = getVolumeName(element.getAttributeValue(field));
                    if (name.startsWith(identity)) {
                        return element;
                    }
                }
                return null;
            }

        };
        return root.getContent(f);
    }

    /**
     * Permet de trouver un volume par son nom et son type (TMA, CTA,...)
     * @param type
     * @param name
     * @return l'lment recherch.
     */
    public Element findElementByName(int type, String name) {
        Element racine = document.getRootElement().getChild("Situation").getChild("VolumeS");
        return findElement(racine, getID(type, name));
    }

    /**
     * Renvoie l'lment dont l'attribut "pk" correspond  <code>idNumber</code> parmi les fils de l'lment <code>racine</code>
     * @param racine 
     * @param idNumber
     * @return L'lment demand ou <code>null</code> si celui-ci n'a pas t trouv.
     */
    public Element findElement(Element racine, String idNumber) {
        final String id = idNumber;
        Filter<Element> f = new AbstractFilter<Element>() {

            @Override
            public Element filter(Object o) {
                if (o instanceof Element) {
                    Element element = (Element) o;
                    if (element.getAttributeValue("pk").equals(id)) {
                        return element;
                    }
                }
                return null;
            }

        };

        List<Element> elements = racine.getContent(f);
        if (elements != null) {
            if (elements.size() > 0)
                return elements.get(0);
        }
        return null;
    }

    public List<Element> findElementsByChildId(Element root, String childParam, String value) {
        final String child = childParam;
        final String childID = value;

        Filter<Element> f = new AbstractFilter<Element>() {

            @Override
            public Element filter(Object o) {
                if (o instanceof Element) {
                    Element element = (Element) o;
                    String pkChild = element.getChild(child).getAttributeValue("pk");
                    if (pkChild.equals(childID)) {
                        return (Element) o;
                    }
                }
                return null;
            }
        };

        return root.getContent(f);
    }

    public Element findNavFixInfosByName(String name) {
        PreparedStatement st;
        String pk = "";
        try {
            st = DatabaseManager.prepareStatement(DatasManager.Type.AIP, "select pk from NavFix where nom = ?");
            st.setString(1, name);
            ResultSet rs = st.executeQuery();
            if (rs.next()) {
                pk = rs.getString(1);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        if (pk.equals("")) {
            return null;
        }
        return findElement(getDocumentRoot().getChild("RadioNavS"), pk);
    }

    /**
     * Renvoie l'identifiant de l'objet de type <code>type</code> et de nom <code>name</code>.
     * @param type le type de l'objet
     * @param name le nom de l'objet
     * @return L'attribut pk qui identifie l'objet dans le fichier xml.
     */
    public static String getID(int type, String name) {
        String pk = null;
        if (type >= AIP.AWY) {
            String table = (type >= AIP.DMEATT) ? "NavFix" : "routes";
            try {
                PreparedStatement st = DatabaseManager.prepareStatement(DatasManager.Type.AIP,
                        "select pk from " + table + " where nom = ?");
                st.setString(1, name);
                ResultSet rs = st.executeQuery();
                if (rs.next()) {
                    pk = rs.getString(1);
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        } else {
            String typeString = type2String(type);
            try {
                PreparedStatement st = DatabaseManager.prepareStatement(DatasManager.Type.AIP,
                        "select pk from volumes where type = ? AND nom = ?");
                st.setString(1, typeString);
                st.setString(2, name);
                ResultSet rs = st.executeQuery();
                if (rs.next()) {
                    pk = rs.getString(1);
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return pk;
    }

    public String getZoneAttributeValue(String zoneID, String attribute) {
        Element zone = findElement(document.getRootElement().getChild("Situation").getChild("VolumeS"), zoneID);
        return zone != null ? zone.getChildText(attribute) : null;
    }

    /**
     * Mme chose que org.jdom.Element.getChildText mais renvoie null si l'enfant n'existe pas au lieu de lever une exception.
     * @param e
     * @param childName
     * @return
     */
    public String getChildText(Element e, String childName) {
        Element child = e.getChild(childName);
        return child != null ? child.getText() : null;
    }

    public String getTerritoireName(String territoireID) {
        Element territoire = findElement(document.getRootElement().getChild("Situation").getChild("TerritoireS"),
                territoireID);
        return territoire.getChildText("Nom");
    }

    /**
     * Renvoie les niveaux plancher et plafond d'une zone, sous forme de couple d'<code>Altitude</code>. 
     * Attention : Ne teste pas si l'lment contient bien un champ plafond et un champ plancher.
     * @param e L'lment dont on cherche le plancher et le plafond.
     * @return Un couple d'<code>Altitude</code> dont le premier lment est le plancher et le second est le plafond.
     * @see Altitude
     */
    public Couple<Altitude, Altitude> getLevels(Element e) {
        Altitude plancher = new Altitude(e.getChild("PlancherRefUnite").getValue(),
                Integer.parseInt(e.getChild("Plancher").getValue()));
        Altitude plafond = new Altitude(e.getChild("PlafondRefUnite").getValue(),
                Integer.parseInt(e.getChild("Plafond").getValue()));
        return new Couple<Altitude, Altitude>(plancher, plafond);
    }

    /**
     * 
     * @return Une liste de couples dont le premier lment est le nom de la route et le deuxime son type.
     */
    public List<Couple<String, String>> getRouteNamesFromDB() {
        ArrayList<Couple<String, String>> routeNames = new ArrayList<Couple<String, String>>();
        try {
            this.getName();
            this.conn = DatabaseManager.selectDB(DatasManager.Type.AIP, this.name);
            PreparedStatement ps = this.conn.prepareStatement("select nom, type from routes");
            ResultSet rs = ps.executeQuery();
            while (rs.next()) {
                routeNames.add(new Couple<String, String>(rs.getString(1), rs.getString(2)));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return routeNames;
    }

    /**
     * Classe conservant l'unit et la rfrence (AMSL,ASFC...) d'un plafond ou plancher fourni pour un Volume, et qui permet d'avoir l'quivalent en FL. 
     * @author VIDAL Adrien
     *
     */
    public class Altitude {
        private int unite;
        private int ref;
        private int originalValue;
        private int FL;
        private String fullText;

        static final int sfc = 0, ft = 1, fl = 2;
        static final int refSFC = 0, amsl = 1, asfc = 2, qnh = 3, unl = 4;

        public Altitude(String refUnite, int value) {
            originalValue = value;
            if (refUnite.startsWith("ft")) {
                FL = value / 100;
                unite = Altitude.ft;
                String reference = refUnite.substring(3);
                if (reference.equals("ASFC")) {
                    this.fullText = value + " ft ASFC";
                    ref = Altitude.asfc;
                } else {
                    this.fullText = value + " ft AMSL";
                    ref = Altitude.amsl;
                }
            }
            if (refUnite.equals("SFC")) {
                FL = 0;
                unite = Altitude.sfc;
                ref = Altitude.refSFC;
                this.fullText = "SFC";
            }
            if (refUnite.equals("FL")) {
                FL = value;
                unite = Altitude.fl;
                ref = Altitude.qnh;
                String valueString = "" + value;
                if (value < 100) {
                    valueString = "0" + value;
                }
                if (value < 10) {
                    valueString = "00" + value;
                }
                this.fullText = "FL " + valueString;
            }
            if (refUnite.equals("UNL")) {
                originalValue = 660;
                FL = 660;
                unite = Altitude.fl;
                ref = Altitude.unl;
                this.fullText = "ILLIMIT";
            }
        }

        public int getUnite() {
            return unite;
        }

        public int getRef() {
            return ref;
        }

        public int getOriginalValue() {
            return originalValue;
        }

        public int getFL() {
            return FL;
        }

        public String getFullText() {
            return fullText;
        }

        public boolean isTerrainConforming() {
            if (ref == Altitude.asfc || ref == Altitude.refSFC)
                return true;
            return false;
        }

        public int getMeters() {
            if (unite == Altitude.sfc)
                return 0;
            if (unite == Altitude.ft)
                return (int) (((double) originalValue) / 3.2808);
            return (int) (((double) originalValue * 100) / 3.2808);
        }
    }

    @Override
    public DatasManager.Type getType() {
        return DatasManager.Type.AIP;
    }

    @Override
    public List<String> getRelevantFileNames() {
        // TODO Auto-generated method stub
        return null;
    }

}