/* ====================================================================
 * Copyright (c) 2004-2005 Open Source Applications Foundation.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions: 
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software. 
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 * ====================================================================
 */

#include "PyLucene.h"
#include <java/io/Reader.h>

#include "org/osafoundation/util/PythonException.h"
#include "org/osafoundation/analysis/PythonAnalyzer.h"
#include "org/osafoundation/analysis/PythonTokenStream.h"
#include "org/osafoundation/analysis/PythonTokenFilter.h"
#include "org/osafoundation/analysis/PythonCharTokenizer.h"
#include "org/apache/lucene/analysis/TokenStream.h"
#include "org/apache/lucene/analysis/TokenFilter.h"
#include "org/apache/lucene/analysis/CharTokenizer.h"
#include "org/apache/lucene/analysis/Token.h"


/**
 * The native functions declared in: 
 *     org.osafoundation.analysis.PythonAnalyzer
 *     org.osafoundation.analysis.PythonTokenStream
 *     org.osafoundation.analysis.PythonTokenFilter
 *     org.osafoundation.analysis.PythonCharTokenizer
 * 
 * @author Andi Vajda
 */

namespace org {
    namespace osafoundation {
        namespace analysis {

            // org.osafoundation.analysis.PythonAnalyzer

            void PythonAnalyzer::incRef(void)
            {
                PythonGIL gil;
                Py_INCREF(*(PyObject **) &pythonAnalyzer);
            }

            void PythonAnalyzer::decRef(void)
            {
                finalizeObject(pythonAnalyzer);
            }

            ::org::apache::lucene::analysis::TokenStream *PythonAnalyzer::tokenStream(jstring fieldName, ::java::io::Reader *reader)
            {
                PythonGIL gil;
                PyObject *pyFieldName = j2p(fieldName);
                PyObject *pyReader = wrap_Reader(reader);
                PyObject *pyts = callPython(*(PyObject **) &pythonAnalyzer, "tokenStream", pyFieldName, pyReader, NULL);

                Py_DECREF(pyFieldName);
                Py_DECREF(pyReader);

                if (!pyts)
                    throw new org::osafoundation::util::PythonException();

                jobject jo;
                jlong ptr;

                *(PyObject **) &ptr = pyts;
                jo = new PythonTokenStream(ptr);
                Py_DECREF(pyts);

                return (::org::apache::lucene::analysis::TokenStream *) jo;
            }

            // org.osafoundation.analysis.PythonTokenStream

            void PythonTokenStream::incRef(void)
            {
                PythonGIL gil;
                Py_INCREF(*(PyObject **) &pythonTokenStream);
            }

            void PythonTokenStream::decRef(void)
            {
                finalizeObject(pythonTokenStream);
            }

            ::org::apache::lucene::analysis::Token *PythonTokenStream::next()
            {
                PythonGIL gil;
                PyObject *pyt = callPython(*(PyObject **) &pythonTokenStream, "next", NULL);

                if (!pyt)
                    throw new org::osafoundation::util::PythonException();

                org::apache::lucene::analysis::Token *token;

                if (!parseArg(pyt, "J",
                              &org::apache::lucene::analysis::Token::class$,
                              &token))
                {
                    Py_DECREF(pyt);
                    return token;
                }
                else
                {
                    PyErr_SetObject(PyExc_TypeError, pyt);
                    Py_DECREF(pyt);
                }                    

                throw new org::osafoundation::util::PythonException();
            }

            // org.osafoundation.analysis.PythonTokenFilter

            void PythonTokenFilter::incRef(void)
            {
                PythonGIL gil;
                Py_INCREF(*(PyObject **) &pythonTokenFilter);
            }

            void PythonTokenFilter::decRef(void)
            {
                finalizeObject(pythonTokenFilter);
            }

            ::org::apache::lucene::analysis::Token *PythonTokenFilter::next()
            {
                PythonGIL gil;
                PyObject *pyt = callPython(*(PyObject **) &pythonTokenFilter, "next", NULL);

                if (!pyt)
                    throw new org::osafoundation::util::PythonException();

                org::apache::lucene::analysis::Token *token;

                if (!parseArg(pyt, "J",
                              &org::apache::lucene::analysis::Token::class$,
                              &token))
                {
                    Py_DECREF(pyt);
                    return token;
                }
                else
                {
                    PyErr_SetObject(PyExc_TypeError, pyt);
                    Py_DECREF(pyt);
                }                    

                throw new org::osafoundation::util::PythonException();
            }

            // org.osafoundation.analysis.PythonCharTokenizer

            void PythonCharTokenizer::incRef(void)
            {
                PythonGIL gil;
                Py_INCREF(*(PyObject **) &pythonCharTokenizer);
            }

            void PythonCharTokenizer::decRef(void)
            {
                finalizeObject(pythonCharTokenizer);
            }

            jboolean PythonCharTokenizer::isTokenChar(jchar c)
            {
                PythonGIL gil;
                wchar_t wc = (wchar_t) c;
                PyObject *pyChar = PyUnicode_FromWideChar(&wc, 1);
                PyObject *pyb = callPython(*(PyObject **) &pythonCharTokenizer, "isTokenChar", pyChar, NULL);

                Py_DECREF(pyChar);

                if (!pyb)
                    throw new org::osafoundation::util::PythonException();
                
                jboolean b = (jboolean) PyObject_IsTrue(pyb);
                Py_DECREF(pyb);

                return b;
            }

            jchar PythonCharTokenizer::normalize(jchar c)
            {
                PythonGIL gil;
                PyObject *pyCharTokenizer = *(PyObject **) &pythonCharTokenizer;

                if (PyObject_HasAttrString(pyCharTokenizer, "normalize"))
                {
                    wchar_t wc = (wchar_t) c;
                    PyObject *pyChar = PyUnicode_FromWideChar(&wc, 1);
                    PyObject *pyc = callPython(pyCharTokenizer, "normalize", pyChar, NULL);

                    Py_DECREF(pyChar);

                    if (!pyc)
                        throw new org::osafoundation::util::PythonException();
                
                    wchar_t w;
                    if (!PyUnicode_AsWideChar((PyUnicodeObject *) pyc, &w, 1))
                        throw new org::osafoundation::util::PythonException();
                    Py_DECREF(pyc);

                    return (jchar) w;
                }

                return CharTokenizer::normalize(c);
            }
        }
    }
}
