#!/usr/bin/python -u
# Copyright or Copr. INRIA/Scilab - Sylvestre LEDRU
#
# Sylvestre LEDRU - <sylvestre.ledru@inria.fr> <sylvestre@ledru.info>
#
# This software is a computer program whose purpose is to generate C++ wrapper
# for Java objects/methods.
#
# This software is governed by the CeCILL  license under French law and
# abiding by the rules of distribution of free software.  You can  use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and  rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty  and the software's author,  the holder of the
# economic rights,  and the successive licensors  have only  limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading,  using,  modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean  that it is complicated to manipulate,  and  that  also
# therefore means  that it is reserved for developers  and  experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and,  more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
# For more information, see the file COPYING

from datatypes.dataGiws import dataGiws
from configGiws import configGiws
from JNIFrameWork import JNIFrameWork

class stringDataGiws(dataGiws):

    nativeType="char *"
    callMethod="CallObjectMethod"
    callStaticMethod="CallStaticObjectMethod"
    temporaryVariableName="myStringBuffer"

    def getTypeSignature(self):
        return "Ljava/lang/String;"

    def getJavaTypeSyntax(self):
        if self.isArray():
            return "jobjectArray"
        else:
            return "jstring"

    def getRealJavaType(self):
        return "java.lang.String"

    def getDescription(self):
        return "Java String"

    def getNativeType(self, ForceNotArray=False, UseConst=False):
        if self.isArray():
            if UseConst:
                pointer = " const*"
            else:
                pointer = "*"
            return ("char" + pointer) + pointer * self.getDimensionArray()
        else:
            if UseConst:
                pointer = " const*"
            else:
                pointer = "*"
            return "char" + pointer

    def __errorMemoryString(self, detachThread):
        # Management of the error when not enought memory to create the string
        if configGiws().getThrowsException():
            errorMgntMemBis="""%sthrow %s::JniBadAllocException(curEnv);"""%(detachThread,configGiws().getExceptionFileName())
        else:
            errorMgntMemBis="""std::cerr << "Could not convert C string to Java UTF string, memory full." << std::endl;%s
            exit(EXIT_FAILURE);"""%(detachThread)
        return errorMgntMemBis

    def specificPreProcessing(self, parameter, detachThread):
        """ Overrides the preprocessing of the array """
        name=parameter.getName()
        # Management of the error when not enought memory to create the string
        if configGiws().getThrowsException():
            errorMgntMem="""%sthrow %s::JniBadAllocException(curEnv);"""%(detachThread,configGiws().getExceptionFileName())
        else:
            errorMgntMem="""std::cerr << "Could not allocate Java string array, memory full." << std::endl;%s
            exit(EXIT_FAILURE);"""%(detachThread)

        errorMgntMemBis = self.__errorMemoryString(detachThread)

        if self.isArray():
            if self.getDimensionArray() == 1:
                return """

                // create java array of strings.
                jobjectArray %s_ = curEnv->NewObjectArray( %sSize, stringArrayClass, NULL);
                if (%s_ == NULL)
                {
                %s
                }

                // convert each char * to java strings and fill the java array.
                for ( int i = 0; i < %sSize; i++)
                {
                jstring TempString = curEnv->NewStringUTF( %s[i] );
                if (TempString == NULL)
                {
                %s
                }

                curEnv->SetObjectArrayElement( %s_, i, TempString);

                // avoid keeping reference on too many strings
                curEnv->DeleteLocalRef(TempString);
                }"""%(name,name,name,errorMgntMem,name,name,errorMgntMemBis,name)
            else:
                return """
                // create java array of array of strings.
                jobjectArray %s_ = curEnv->NewObjectArray( %sSize, curEnv->FindClass("[Ljava/lang/String;"), NULL);
                if (%s_ == NULL)
                {
                %s
                }

                for ( int i = 0; i < %sSize; i++)
                {
                jobjectArray %sLocal = curEnv->NewObjectArray( %sSizeCol, stringArrayClass, NULL);
                // convert each char * to java strings and fill the java array.
                for ( int j = 0; j < %sSizeCol; j++) {
                jstring TempString = curEnv->NewStringUTF( %s[i][j] );

                if (TempString == NULL)
                {
                %s
                }

                curEnv->SetObjectArrayElement( %sLocal, j, TempString);

                // avoid keeping reference on too many strings
                curEnv->DeleteLocalRef(TempString);
                }
                curEnv->SetObjectArrayElement(%s_, i, %sLocal);
                curEnv->DeleteLocalRef(%sLocal);

                }"""%(name,name,name,errorMgntMem,name,name,name,name,name,errorMgntMemBis,name,name,name,name)

        else:
            # Need to store is for the post processing (delete)
            self.parameterName=name
            tempName=name+"_"
            return """
            jstring %s = curEnv->NewStringUTF( %s );
            if (%s != NULL && %s == NULL)
            {
            %s
            }

            """%(tempName,name,name,tempName,errorMgntMemBis)

    def specificPostProcessing(self, detachThread):
        """ Called when we are returning a string or an array of string """
        # We are doing an exception check here JUST in this case because
        # in methodGiws::__createMethodBody we usually do it at the end
        # of the method just after deleting the variable
        # but when dealing with string, in this method, we are calling some
        # methods which override the "exception engine" which drive the JNI
        # engine crazy.

        str=JNIFrameWork().getExceptionCheckProfile(detachThread)

        str=str+"if (res != NULL) { "

        if self.isArray():
            strCommon=""
            strDeclaration=""
            if configGiws().getDisableReturnSize()==True:
                strCommon+="int lenRow;"
            else:
                # The size of the array is returned as output argument of the function
                strDeclaration="*"
            strCommon+="""
            %s lenRow = curEnv->GetArrayLength(res);
            """%(strDeclaration)
            self.temporaryVariableName="arrayOfString"
            if self.getDimensionArray() == 1:
                str+=strCommon+"""
                char **arrayOfString;
                arrayOfString = new char *[%slenRow];
                for (jsize i = 0; i < %slenRow; i++){
                jstring resString = reinterpret_cast<jstring>(curEnv->GetObjectArrayElement(res, i));
                const char *tempString = curEnv->GetStringUTFChars(resString, 0);
                arrayOfString[i] = new char[strlen(tempString) + 1];

                strcpy(arrayOfString[i], tempString);
                curEnv->ReleaseStringUTFChars(resString, tempString);
                curEnv->DeleteLocalRef(resString);
                }
                """%(strDeclaration, strDeclaration)
                return str
            else:
                if configGiws().getDisableReturnSize()==True:
                    str+="int lenCol;"
                str+=strCommon+"""
                char ***arrayOfString;
                arrayOfString = new char **[%slenRow];
                for (jsize i = 0; i < %slenRow; i++){ /* Line of the array */
                jobjectArray resStringLine = reinterpret_cast<jobjectArray>(curEnv->GetObjectArrayElement(res, i));
                %slenCol = curEnv->GetArrayLength(resStringLine);
                arrayOfString[i]=new char*[%slenCol];
                for (jsize j = 0; j < %slenCol; j++){
                jstring resString = reinterpret_cast<jstring>(curEnv->GetObjectArrayElement(resStringLine, j));
                const char *tempString = curEnv->GetStringUTFChars(resString, 0);
                arrayOfString[i][j] = new char[strlen(tempString) + 1];
                strcpy(arrayOfString[i][j], tempString);
                curEnv->ReleaseStringUTFChars(resString, tempString);
                curEnv->DeleteLocalRef(resString);
}
                curEnv->DeleteLocalRef(resStringLine);
                 }
                """%(strDeclaration, strDeclaration, strDeclaration, strDeclaration, strDeclaration)

                return str

        else:
            if hasattr(self,"parameterName"):
                str+="""curEnv->DeleteLocalRef(%s);"""%(self.parameterName+"_")
            str=str+"""

            const char *tempString = curEnv->GetStringUTFChars(res, 0);
            char * %s = new char[strlen(tempString) + 1];
            strcpy(%s, tempString);
            curEnv->ReleaseStringUTFChars(res, tempString);
            curEnv->DeleteLocalRef(res);
            """%(self.temporaryVariableName, self.temporaryVariableName)

            return str


    def getReturnSyntax(self):
        str=""
        if self.isArray():
            str = str + """
            curEnv->DeleteLocalRef(res);
            return arrayOfString;
            """
        else:
            str = str + """
            return %s;
            """%(self.temporaryVariableName)
            str = str + """ } else {
            curEnv->DeleteLocalRef(res);
                return NULL;
            }"""
        return str
