/*****************************************************************************
FILE:               O2CI7Context.m
LANGUAGE:           Objective-C
SYSTEM:             GNUstep
USER-INTERFACE:     None
DESCRIPTION

    This class is a private class of the GNUstep/db adaptor to the 
    Oracle databases.
    It implements an object interface to the O2CI7 primitives.
    It's implementation is based on the O2CI7 v7, and should be compatible
    with, at least, both Oracle7 and Oracle8 databases.

AUTHORS
    <PJB> Pascal J. Bourguignon <pjb@imaginet.fr>
MODIFICATIONS
    1999/07/25 Creation.
BUGS
    - ...
LEGAL
    Written by:  Pascal J. Bourguignon <pjb@imaginet.fr>
    Funds from:  Orange Concept (http://www.orange-concept.com/)
    Date:        August 1999 - February 2000

    This file is part of the Oracle7 Adaptor, GNUstep Database Library.
    The Oracle7 Adaptor allows access to Oracle[678] databases from GDL.

    Copyright (C) 2000 Free Software Foundation, Inc.

    This  library is  free software;  you can  redistribute  it and/or
    modify it under the terms of the GNU Lesser General Public License
    as published by the Free  Software Foundation; either version 2 of
    the License, or (at your option) any later version.

    This library  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
    Lesser General Public License for more details.

    You should have  received a copy of the  GNU Lesser General Public
    License  along  with this  library;  if  not,  write to  the  Free
    Software  Foundation, Inc.,  59 Temple  Place, Suite  330, Boston,
    MA 02111-1307 USA
*****************************************************************************/

#include <O2CI7Context.h>
#include <Oracle7Utilities.h>




// ------------------------------------------------------------------------ //

@interface O2CI7Context(Private)

    -(void)string:(NSString*)string toText:(text**)aText;

@end //O2CI7Context(Private)

// ------------------------------------------------------------------------ //

@implementation O2CI7Context(Private)

    -(void)string:(NSString*)string toText:(text**)aText
    {
        if(string==nil){
            if((*aText)!=(text*)0){
                free(*aText);
                (*aText)=(text*)0;
            }
        }else{
            unsigned len=[string cStringLength];
            if((*aText)==(text*)0){
                (*aText)=(text*)malloc(sizeof(text)*(len+1));
            }else if(strlen(*aText)<len){
                free(*aText);
                (*aText)=(text*)malloc(sizeof(text)*(len+1));
            }
            [string getCString:(*aText)];
        }
    }//string:toText:;


@end //O2CI7Context(Private)

// ------------------------------------------------------------------------ //

@implementation O2CI7Context


// NSObject methods:

    -(id)init
    {
        self=[super init];
        if(self!=nil){
            memset((void*)&lda,0,sizeof(lda));
            memset((void*)&hda,0,sizeof(hda));
            isConnected=NO;
            doAutoCommit=NO; // This is the default of O2CI7.
            tname=(text*)0;
            tword=(text*)0;
            tstring=(text*)0;
        }
        return(self);
    }//init;


    -(void)dealloc
    {
        if(isConnected){
            [self logout];
        }
        if(tname!=(text*)0){
            free(tname);
        }
        if(tword!=(text*)0){
            free(tword);
        }
        if(tstring!=(text*)0){
            free(tstring);
        }
        [super dealloc];
    }//dealloc;


// O2CI7Context methods:

    +(void)initializeWithMode:(ub4)mode
    {
        static BOOL initialized=NO;
        if(!initialized){
            opinit(mode);
            initialized=YES;
        }
    }//initializeWithMode:;



    -(BOOL)loginName:(NSString*)name 
            password:(NSString*)word 
            connectString:(NSString*)string
    {
        [self cleanErrorMessages];
        if(isConnected){
            [self reportErrorAlreadyConnected];
            return(NO);
        }else{
            // We're  not sure that oparse don't change its text 
            // parameters; they're not (const text*).
            [self string:name   toText:&tname];
            [self string:word   toText:&tword];
            [self string:string toText:&tstring];
            if(olog(&lda,(ub1*)&hda,tname,-1,tword,-1,tstring,-1,0)){
                [self reportErrorFromOCI];
                return(NO);
            }else{
                isConnected=YES;
                [self setAutoCommit:doAutoCommit];
                return(YES);
            }
        }
    }//loginName:passWord:connectString:;


    -(BOOL)logout
    {
        [self cleanErrorMessages];
        if(isConnected){
            if(ologof(&lda)){
                [self reportErrorOnLogout];
                return(NO);
            }else{
                isConnected=NO;
                return(YES);
            }
        }else{
            return(NO);
        }
    }//logout;


    -(BOOL)isConnected
    {
        return(isConnected);
    }//isConnected;


    -(BOOL)setAutoCommit:(BOOL)autoCommit
    {
        [self cleanErrorMessages];
        doAutoCommit=autoCommit;
        if(isConnected){
            if(doAutoCommit?ocon(&lda):ocof(&lda)){
                [self reportErrorFromOCI];
                return(NO);
            }else{
                return(YES);
            }
        }else{
            return(YES);
        }
    }//setAutoCommit:;


    -(BOOL)transCommit
    {
        [self cleanErrorMessages];
        if(isConnected){
            if(ocom(&lda)){
                [self reportErrorFromOCI];
                return(NO);
            }else{
                return(YES);
            }
        }else{
            [self reportErrorNotConnected];
            return(NO);
        }
    }//transCommit;


    -(BOOL)transRollback
    {
        [self cleanErrorMessages];
        if(isConnected){
            if(orol(&lda)){
                [self reportErrorFromOCI];
                return(NO);
            }else{
                return(YES);
            }
        }else{
            [self reportErrorNotConnected];
            return(NO);
        }
    }//transRollback;



    -(O2CI7Cursor*)openCursor
    {
        O2CI7Cursor* cursor;
        [self cleanErrorMessages];
        cursor=[[[O2CI7Cursor alloc]initWithContext:self]autorelease];
        if(cursor!=nil){
            if([cursor open]){
                return(cursor);
            }else{
                [cursor reportErrorFromOCI];
                return(nil);
            }
        }else{
            [self reportErrorMessage:NSLocalizedStringFromTableInBundle(@"Could not allocate or initialize the Oracle cursor.",@"O2CI7Context",Oracle7Utilities_Bundle(),@"Error message reported when the Oracle cursor cannot be allocated or initialized.")];
            return(nil);
        }
    }//openCursor;




    -(void)reportErrorFromOCI
    {
        [self reportErrorCode:lda.rc functionCode:lda.fc];
    }//reportErrorFromOCI;


    -(void)reportErrorOnLogout
    {
        [self reportErrorMessage:NSLocalizedStringFromTableInBundle(@"An error occured while disconnecting from the database (sorry, no more specific message).",@"O2CI7Context",Oracle7Utilities_Bundle(),@"Error message given when an error occurs on database log out.")];
    }//reportErrorOnLogout;


    -(void)reportErrorAlreadyConnected
    {
        [self reportErrorMessage:NSLocalizedStringFromTableInBundle(@"Context already connected to the database.",@"O2CI7Context",Oracle7Utilities_Bundle(),@"Error message given when the client program tries to connect twice to the database (once is enought).")];
    }//reportErrorAlreadyConnected;


    -(void)reportErrorNotConnected
    {
        [self reportErrorMessage:NSLocalizedStringFromTableInBundle(@"Context not connected to the database.",@"O2CI7Context",Oracle7Utilities_Bundle(),@"Error message given when the client program tries to access the database whithout being connected.")];
    }//reportErrorNotConnected;


    -(void)reportErrorCode:(ub2)rc functionCode:(ub1)fc
    {
        NSString* errorMessage=[self errorMessageForCode:rc];
        [self reportErrorMessage:errorMessage];
        ///*DEBUG*/       NSLog(@"OCI Error:    %@\n",errorMessage);
        if(fc>0){
            NSString* functionName=[self functionNameForCode:fc];
            [self reportErrorMessage:functionName];
            ///*DEBUG*/   NSLog(@"OCI Function: %@\n",functionName);
        }
    }//reportErrorCode:functionCode:;



    -(NSString*)errorMessageForCode:(ub2)rc
    {
        text  errorMessage[512];
        sword result=oerhms(&lda,rc,errorMessage,(sword)sizeof(errorMessage));
        return([NSString stringWithCString:errorMessage]);
    }//errorMessageForCode:;


    -(NSString*)functionNameForCode:(ub1)fc
    {
        static const int oci_func_tab_size
            =(sizeof(oci_func_tab)/sizeof(oci_func_tab[0]));
        if((0<fc)&&(fc<oci_func_tab_size)){
            return([NSString stringWithCString:oci_func_tab[fc]]);
        }else{
            return(@"");
        }
    }//functionNameForCode:;

    

    -(Lda_Def*)lda
    {
        return(&lda);
    }//lda;


@end // O2CI7Context;



/*** O2CI7Context.m                   -- 2000-02-21 07:11:19 -- PJB ***/
