/* Generated by Together */

package org.esw.thes.conv.eh;
import java.io.File;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Model;
import java.util.logging.Logger;
import java.util.Hashtable;
import java.util.Vector;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.FileInputStream;
import java.util.StringTokenizer;
import com.hp.hpl.jena.rdf.model.Resource;
import org.esw.thes.vocab.SKOS;
import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.vocabulary.DC;
import com.hp.hpl.jena.vocabulary.RDFS;
import java.io.FileOutputStream;
import java.util.NoSuchElementException;
import com.hp.hpl.jena.vocabulary.XSD;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.ResIterator;
import java.util.Iterator;

public class Converter {

    Model model;
    Resource scheme;
    Hashtable teHash = new Hashtable();
    Hashtable tuHash = new Hashtable();
    Vector nodeLabels = new Vector();

    Logger log = Logger.getLogger("org.esw.thes.conv.eh.Converter");

    public Converter(File classification_groups, File terms, File term_preferences, File  term_uses, File term_relation, File output)
    {
        try
        {
            initModel();
            processGroupsTable(classification_groups);
            processTermsTable(terms);
            processTermPreferencesTable(term_preferences);
            processTermUsesTable(term_uses);
            processTermRelationTable(term_relation);
            serialiseModel(output);
            log.info("Conversion done.");
        }
        catch (Exception ex)
        {
            log.severe("Conversion failed.");
            ex.printStackTrace();
        }
    }

    public static void main(String[] argv) {
        try
        {
            File classification_groups = new File(argv[0]);
            File terms = new File(argv[1]);
            File term_preferences = new File(argv[2]);
            File term_uses = new File(argv[3]);
            File term_relation = new File(argv[4]);
            File output = new File(argv[5]);
            new Converter(classification_groups,terms,term_preferences,term_uses,term_relation,output);
        }
        catch (ArrayIndexOutOfBoundsException ex)
        {
            System.out.println("Usage:\nConverter [classification_groups] [terms] [term_preferences] [term_uses] [term_relations] [output]");
        }
    }

    private void initModel() throws Exception
    {
        model = ModelFactory.createMemModelMaker().createModel();

        //Create a resource for the scheme
        scheme = model.createResource();
        scheme.addProperty(RDF.type,SKOS.ConceptScheme);

        //Manually add the top concept because it's not in the tables
        Resource top = model.createResource();
        top.addProperty(RDF.type,SKOS.TopConcept);
        top.addProperty(SKOS.inScheme,scheme);
        top.addProperty(SKOS.prefLabel,"AIRCRAFT");
    }

    private void processGroupsTable(File table) throws Exception
    {
/*
"CLA_GR_UID","DESCRIPTION","NAME","CLASS_TYPE","STATUS","OPS_SET"
225,,"AIRCRAFT TYPE","T","O",
*/
        log.info("Processing.");
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(table)));
        //Discard first line
        reader.readLine();
        String line = reader.readLine();
        Tokenizer toks = new Tokenizer(line);
        String cla_gr_uid = toks.nextToken();
        String description = toks.nextToken();
        String name = toks.nextToken();
        //Add scheme meta-properties
        scheme.addProperty(DC.title,name);
        scheme.addProperty(DC.description,description);
        reader.close();
    }

    private void processTermsTable(File table) throws Exception
    {
/*
"CLA_GR_UID","THE_TE_UID","TERM","INDEX_TERM","SCOPE_NOTE","STATUS","IMAGE_EXISTS"
225,111367,"LANCASTER","Y","Four-engined bomber, developed by Avro from the twin-engined Manchester. Entered service in 1942 as the RAF's principal night bomber and took part in the 1,000 bomber raids as well as the famous Dam Busters raid.","P",
*/
        log.info("Processing.");
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(table)));
        //Discard first line
        reader.readLine();
        //Process records
        String line = reader.readLine();
        while (line!=null)
        {
            //Parse the record
            String cla_gr_uid,the_te_uid,term,index_term,scope_note,status;
            Tokenizer toks = new Tokenizer(line);
            cla_gr_uid = toks.nextToken();
            the_te_uid = toks.nextToken();
            term = toks.nextToken();
            index_term = toks.nextToken();
            scope_note = toks.nextToken();
            status = toks.nextToken();
//            log.info("Parsed record: ["+cla_gr_uid+"@"+the_te_uid+"@"+term+"@"+index_term+"@"+scope_note+"@"+status+"]");

            //Add item to teHash
            teHash.put(the_te_uid,term);

            //Create a skos:Concept if index_term='Y'
            if (index_term.equals("Y"))
            {
                Resource concept = model.createResource();
                concept.addProperty(RDF.type,SKOS.Concept);
                concept.addProperty(SKOS.prefLabel,term);
                concept.addProperty(SKOS.inScheme,scheme);
                concept.addProperty(SKOS.scopeNote,scope_note);
            }

            //Create an skos:Array if index_term='N' and status='P'
            if (index_term.equals("N") && status.equals("P"))
            {
                Resource array = model.createResource();
                array.addProperty(RDF.type,SKOS.Array);
                array.addProperty(RDFS.label,term);
                array.addProperty(SKOS.members,RDF.nil);
                array.addProperty(SKOS.ordered,"false");
                nodeLabels.add(term);
            }

            line = reader.readLine();
        }
        reader.close();
    }

    private void processTermPreferencesTable(File table) throws Exception
    {
/*
"THE_TE_UID_1","THE_TE_UID_2"
111425,111363
*/
        log.info("Processing.");
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(table)));
        //Discard first line
        reader.readLine();
        //Process records
        String line = reader.readLine();
        while (line!=null)
        {
            Tokenizer toks = new Tokenizer(line);
            String id1 = toks.nextToken();
            String id2 = toks.nextToken();
            String term1 = (String) teHash.get(id1);
            String term2 = (String) teHash.get(id2);
            //Get concept which has term2 as prefLabel
            Resource concept = model.listSubjectsWithProperty(SKOS.prefLabel,term2).nextResource();
            concept.addProperty(SKOS.altLabel,term1);
            line = reader.readLine();
        }
        reader.close();
    }

    private void processTermUsesTable(File table) throws Exception
    {
/*
"TH_T_U_UID","TERM","CLA_GR_UID","BROAD_TERM_U_UID","TOP_TERM_U_UID"
175943,"HAMPDEN",225,153785,167503
*/
        log.info("Processing.");
        buildTuHash(table);
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(table)));
        //Discard first line
        reader.readLine();
        //Process records
        String line = reader.readLine();
        while (line != null)
        {
            Tokenizer toks = new Tokenizer(line);
            String th_t_u_uid = toks.nextToken();
            String term = toks.nextToken();
            String cla_gr_uid = toks.nextToken();
            String broad_term_u_uid = toks.nextToken();
            String top_term_u_uid = toks.nextToken();
//            log.info("Parsed record: ["+th_t_u_uid+"@"+term+"@"+cla_gr_uid+"@"+broad_term_u_uid+"@"+top_term_u_uid+"]");
            String broadTerm = (String) tuHash.get(broad_term_u_uid);
//            log.info("Found value for broad term from tuHash ["+broadTerm+"]");

            //if the term is a node label then set up the corresponding array
            if (nodeLabels.contains(term))
            {
                //TODO - array stuff
                //Get concept for broad term
                Resource concept = null;
                try
                {
                    concept = model.listSubjectsWithProperty(SKOS.prefLabel,broadTerm).nextResource();
                }
                catch (NoSuchElementException ex)
                {
                    log.warning("Could not find concept for broad term ["+broadTerm+"]");
                }
                //Get array for term
                Resource array = null;
                try
                {
                    array = model.listSubjectsWithProperty(RDFS.label,term).nextResource();
                }
                catch (NoSuchElementException ex)
                {
                    log.warning("Could not find array for label ["+term+"]");
                }
                //Add array to the concept
                if (concept != null && array != null)
                    concept.addProperty(SKOS.array,array);
            }

            //else if the broad term is a node label
            else if (nodeLabels.contains(broadTerm))
            {
                //TODO - array stuff
                //Get array for broad term
                Resource array = null;
                try
                {
                    array = model.listSubjectsWithProperty(RDFS.label,broadTerm).nextResource();
                }
                catch (NoSuchElementException ex)
                {
                    log.warning("Could not find array for label ["+broadTerm+"]");
                }
                //Get concept for term
                Resource concept = null;
                try
                {
                    concept = model.listSubjectsWithProperty(SKOS.prefLabel,term).nextResource();
                }
                catch (NoSuchElementException ex)
                {
                    log.warning("Could not find concept for term ["+term+"]");
                }
                //Add concept to the array members
                if (array != null && concept != null)
                {
                    Statement s = array.getProperty(SKOS.members);
                    Resource firstMember = s.getResource();
                    if (firstMember.equals(RDF.nil))
                    {
                        model.remove(s);
                        Resource r = model.createResource();
                        array.addProperty(SKOS.members,r);
                        r.addProperty(RDF.first,concept);
                        r.addProperty(RDF.rest,RDF.nil);
                    }
                    else
                    {
                        s = firstMember.getProperty(RDF.rest);
                        Resource nextMember = s.getResource();
                        while (!nextMember.equals(RDF.nil))
                        {
                            firstMember = nextMember;
                            s = nextMember.getProperty(RDF.rest);
                            nextMember = s.getResource();
                        }
                        model.remove(s);
                        Resource r = model.createResource();
                        firstMember.addProperty(RDF.rest,r);
                        r.addProperty(RDF.first,concept);
                        r.addProperty(RDF.rest,RDF.nil);
                    }
                }
            }

            //else
            else
            {
                Resource parent = null;
                Resource child = null;
                try
                {
                    child = model.listSubjectsWithProperty(SKOS.prefLabel,term).nextResource();
                }
                catch (NoSuchElementException ex)
                {
                    log.warning("Error in thesaurus data: no concept found with prefLabel ["+term+"]");
                }
                try
                {
                    parent = model.listSubjectsWithProperty(SKOS.prefLabel,broadTerm).nextResource();
                }
                catch (NoSuchElementException ex)
                {
                    log.warning("Error in thesaurus data: no concept found with prefLabel ["+broadTerm+"]");
                }
                if (child != null && parent != null)
                {
                    child.addProperty(SKOS.broader,parent);
                    parent.addProperty(SKOS.narrower,child);
                }
            }
            line = reader.readLine();
        }
        reader.close();
        addArrayImplications();
    }

    private void addArrayImplications()
    {
        ResIterator rit = model.listSubjectsWithProperty(RDF.type,SKOS.Array);
        while (rit.hasNext())
        {
            Resource array = rit.nextResource();
            Resource parent = null;
            try
            {
                parent = model.listSubjectsWithProperty(SKOS.array,array).nextResource();
            }
            catch (NoSuchElementException ex)
            {
                log.warning("No parent found for array: "+array.getProperty(RDFS.label).getString());
            }
            if (parent != null)
            {
                Resource member = array.getProperty(SKOS.members).getResource();
                while (!member.equals(RDF.nil))
                {
                    Resource child = member.getProperty(RDF.first).getResource();
                    parent.addProperty(SKOS.narrower,child);
                    child.addProperty(SKOS.broader,parent);
                    member = member.getProperty(RDF.rest).getResource();
                }
            }
        }
    }

    private void buildTuHash(File table) throws Exception
    {
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(table)));
        //Discard first line
        reader.readLine();
        //Process records
        String line = reader.readLine();
        while (line != null)
        {
            Tokenizer toks = new Tokenizer(line);
            tuHash.put(toks.nextToken(),toks.nextToken());
            line = reader.readLine();
        }
        reader.close();
        //Manually add top term
        tuHash.put("167503","AIRCRAFT");
    }

    private void processTermRelationTable(File table) throws Exception
    {
        log.info("Processing.");
    }

    private void serialiseModel(File output) throws Exception
    {
        log.info("Serializing model.");
        FileOutputStream outStream = new FileOutputStream(output);
        model.setNsPrefix("skos","http://www.w3.org/2004/02/skos/core#");
        model.write(outStream,"RDF/XML");
        outStream.flush();
        outStream.close();
    }
}
