package org.argosdic.search;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.SimpleAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexWriter;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;

/**
 * SearchIndexer.java
 * @author Xavier Cho
 * @version $Revision: 1.2 $ $Date: 2003/09/30 12:50:23 $
 */
public class SearchIndexer extends DefaultHandler implements ContentHandler {
    private static Log log = LogFactory.getLog(SearchIndexer.class);

    private StringWriter writer;
    private IndexWriter indexer;
    private String source;
    private String target;
    private Analyzer analyzer;
    private String element;
    private String key;
    private String value;

    /** Default parser name. */
    protected static final String DEFAULT_PARSER_NAME = "org.apache.xerces.parsers.SAXParser"; //$NON-NLS-1$

    public SearchIndexer(String source, String target) throws IOException {
        this.source = source;
        this.target = target;
        this.analyzer = new SimpleAnalyzer();

        this.indexer = new IndexWriter(new File(target), analyzer, true);
    }

    public SearchIndexer(String source, String target, String analyzerClass)
        throws
            IOException,
            ClassNotFoundException,
            InstantiationException,
            IllegalAccessException {
        this.source = source;
        this.target = target;

        if (analyzerClass != null) {
            if (log.isInfoEnabled()) {
                log.info("Instantiating anayzer : " + analyzerClass); //$NON-NLS-1$
            }

            Class cl = Class.forName(analyzerClass);
            this.analyzer = (Analyzer) cl.newInstance();
        } else {
            this.analyzer = new SimpleAnalyzer();
        }

        this.indexer = new IndexWriter(new File(target), analyzer, true);
    }

    /** Characters. */
    public void characters(char[] ch, int offset, int length)
        throws SAXException {

        if (writer != null) {
            writer.write(ch, offset, length);
        }
    }

    /**
     * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
     */
    public void startElement(
        String uri,
        String localName,
        String qName,
        Attributes attributes)
        throws SAXException {

        this.element = localName;
        this.writer = new StringWriter();
    }

    /**
     * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
     */
    public void endElement(String uri, String localName, String qName)
        throws SAXException {

        if (writer != null) {
            try {
                if (localName.equals("key")) { //$NON-NLS-1$
                    this.key = writer.toString();
                } else {
                    this.value = writer.toString();

                    Document document = new Document();

                    Field field = Field.Text("word", key); //$NON-NLS-1$
                    document.add(field);

                    field = Field.UnIndexed("definition", value); //$NON-NLS-1$
                    document.add(field);

                    if (log.isDebugEnabled()) {
                        log.debug("Indexing definition for : " + key); //$NON-NLS-1$
                    }

                    indexer.addDocument(document);
                }

                writer.close();
            } catch (Exception e) {
            }
            this.writer = null;
        }
    }

    /**
     * @see org.xml.sax.ContentHandler#endDocument()
     */
    public void endDocument() throws SAXException {
        try {
            indexer.optimize();
            indexer.close();
        } catch (Exception e) {
            String msg = "Unable to save index database : " + e.toString(); //$NON-NLS-1$
            if (log.isErrorEnabled()) {
                log.error(msg, e);
            }
        }
    }

    /**
     * @return
     */
    public Analyzer getAnalyzer() {
        return analyzer;
    }

    /**
     * @param analyzer
     */
    public void setAnalyzer(Analyzer analyzer) {
        this.analyzer = analyzer;
    }

    /**
     * @return
     */
    public String getSource() {
        return source;
    }

    /**
     * @param source
     */
    public void setSource(String source) {
        this.source = source;
    }

    /**
     * @return
     */
    public String getTarget() {
        return target;
    }

    /**
     * @param target
     */
    public void setTarget(String target) {
        this.target = target;
    }

    private static void printUsage() {
        System.out.print("Usage : java -cp (classpath) "); //$NON-NLS-1$
        System.out.print("org.argosdic.search.SearchIndexer "); //$NON-NLS-1$
        System.out.println("[options] (source file) [(target directory)]"); //$NON-NLS-1$
        System.out.println();
        System.out.println("\t-help : print usage(this screen)."); //$NON-NLS-1$
        System.out.println("\t-analyzer=(class name) : specify analyzer class."); //$NON-NLS-1$
    }

    /** Main. */
    public static void main(String[] args) throws Exception {
        XMLReader parser = null;

        String source = null;
        String target = null;
        String analyzer = null;

        for (int i = 0; i < args.length; i++) {
            String arg = args[i].trim();

            if (arg.startsWith("-help")) { //$NON-NLS-1$
                printUsage();
                System.exit(0);
            } else if (arg.startsWith("-analyzer=")) { //$NON-NLS-1$
                analyzer = arg.substring(10);
            } else if (source == null) {
                source = arg;
            } else if (target == null) {
                target = arg;
            } else {
                break;
            }
        }

        if (source == null || target == null) {
            printUsage();
            System.exit(0);
        }

        try {
            File file = new File(source);

            if (!file.exists() || !file.canRead() || file.isDirectory()) {
                System.err.println("Unable to read the source file : " + source); //$NON-NLS-1$
                System.exit(-1);
            }

            file = new File(target);

            if (!file.exists()) {
                if (!file.mkdirs()) {
                    System.err.println("Unable to create the target directory : " + source); //$NON-NLS-1$
                    System.exit(-1);
                }
            } else if (!file.isDirectory()) {
                System.err.println("Target path is not a directory : " + source); //$NON-NLS-1$
                System.exit(-1);
            }

            ContentHandler handler =
                new SearchIndexer(source, target, analyzer);

            parser = XMLReaderFactory.createXMLReader(DEFAULT_PARSER_NAME);
            parser.setContentHandler(handler);

            long startTime = System.currentTimeMillis();

            parser.parse(new File(source).toURL().toExternalForm());

            long elapsedTime = (System.currentTimeMillis() - startTime) / 1000;

            System.out.println();
            System.out.println("Elapsed time : " + elapsedTime + " seconds."); //$NON-NLS-1$ //$NON-NLS-2$
        } catch (SAXParseException e) {
            String msg = "Parse error has occurred while reading the source file : " + e.toString(); //$NON-NLS-1$
            System.err.println(msg);

            if (log.isErrorEnabled()) {
                log.error(msg, e);
            }

            System.exit(-1);
        } catch (Exception e) {
            String msg = "Unhandled exception has occurred : " + e.toString(); //$NON-NLS-1$
            System.err.println(msg);

            if (log.isErrorEnabled()) {
                log.error(msg, e);
            }

            System.exit(-1);
        }
    }
}