/*

CLASS {NATIVE_DB|_CSharp_OLE_version_there_are_problems_there},
NATIVE, UNTESTED:

IMPORT, ANYWAY: {Stream} .

FUN Check_blobs_are_supported ==> BOOL :  RESULT = TRUE .

TEST of_supported:
     ASSERT Check_blobs_are_supported .
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data;
using System.Data.Common;
using System.Data.OleDb;
using System.Data.SqlClient;
using System.Data.SqlTypes;

using System.IO;

using AL4;
using AL4_project;

public class NATIVE_DB
{
    
    public static List<NATIVE_DB> All_db = new List<NATIVE_DB>();
    public List<DbTransaction> All_transactions = new List<DbTransaction>();
    public int Level_transaction = -1;

    public bool use_OleDb;
    public string Connection_string;
    public DbConnection S_c;
    public DbCommand Sql;
    public DbDataReader D_r;

    public static int DB_Create_connection(string Connection, string User,
        int Provider_1OLE)
    {
        if (All_db.Count == 0)
            All_db.Add(new NATIVE_DB("", false));
        int i = All_db.IndexOf(null);
        if (i < 0)
        {
            i = All_db.Count;
            All_db.Add(null);
        }
        if (User != "" && !Connection.Contains("User=")) 
        	Connection += ";User=" + User ;
        All_db[i] = new NATIVE_DB(Connection, Provider_1OLE == 1);
        return i;
    }

    public static bool DB_Connect(int Handle, string Password)
    {
        NATIVE_DB db = All_db[Handle];
        try
        {
            string Connection = db.Connection_string;
            if (Password != "") Connection += ";Password=" + Password ;
            db.S_c.ConnectionString = Connection;
            db.S_c.Open();
            return db.S_c.State == System.Data.ConnectionState.Open;
        }
        catch(Exception E)
        {
            AL4_system.Any_exception(E);
        }
        return false;
    }

    public NATIVE_DB(string Connection, bool use_Ole_Db)
    {
        use_OleDb = use_Ole_Db;
        if (use_Ole_Db)
            S_c = new OleDbConnection();
        else
            S_c = new SqlConnection();
        Connection_string = Connection;
    }
    
    public static bool DB_Is_connected(int Handle)
    {
        try
        {
            NATIVE_DB db = All_db[Handle];
            return db.S_c != null && 
                   db.S_c.State == System.Data.ConnectionState.Open;
        }
        catch(Exception E)
        {
            AL4_system.Any_exception(E);
        }
        return false;
    }

    public static void DB_Disconnect(int Handle)
    {
        try
        {
            NATIVE_DB db = All_db[Handle];
            db.S_c.Close();
            All_db[Handle] = null;
        }
        catch(Exception E)
        {
            AL4_system.Any_exception(E);
        }
    }
    
    public static void DB_Destroy_connection(int Handle)
    {
        try
        {
            NATIVE_DB db = All_db[Handle];
            if (db.S_c != null)
            {
                if (db.S_c.State == System.Data.ConnectionState.Open)
                    db.S_c.Close();
                db.S_c.Dispose();
                db.S_c = null;
            }
            All_db[Handle] = null;
        }
        catch(Exception E)
        {
            AL4_system.Any_exception(E);
        }
    }
    
    public static int DB_Begin_transaction(int Handle)
    {
        try
        {
            NATIVE_DB db = All_db[Handle];
            
            int i = db.All_transactions.IndexOf(null);
            if (i < 0)
            {
                i = db.All_transactions.Count;
                db.All_transactions.Add(null);
            }
            db.All_transactions[i] = db.S_c.BeginTransaction();
            db.Level_transaction = i;
            return i;
        }
        catch(Exception E)
        {
            AL4_system.Any_exception(E);
            return 0;
        }
    }
    
    public static void DB_End_transaction(int Handle, int Transaction_handle,
        bool Commited)
    {
        try
        {
            NATIVE_DB db = All_db[Handle];
            DbTransaction S_t = db.All_transactions[Transaction_handle];
            if (Commited) S_t.Commit();
            else          S_t.Rollback();
            db.All_transactions[Transaction_handle] = null;
            db.Level_transaction -= 1;
        }
        catch(Exception E)
        {
            AL4_system.Any_exception(E);
        }
    }
    
    public static int DB_Execute(int Handle, string Sql_text, DynAObjHard Blobs)
    {
        int RESULT = 0;
        try
        {
            NATIVE_DB db = All_db[Handle];
            db.Sql = db.S_c.CreateCommand();
            
            if (db.Level_transaction >= 0)
            {
            	db.Sql.Transaction = db.All_transactions[db.Level_transaction];
            }
            
            db.Sql.CommandText = Sql_text;
            
            for (int i = 0; i < Blobs.Count; i++)
            {
                DB_Setup_blob_param(Handle, Blobs.Base[i], i);
            }
            
            RESULT = db.Sql.ExecuteNonQuery();
        }
        catch(Exception E)
        {
            AL4_system.Add_error_descr(E.GetType().Name + ": " + E.Message 
            + "\n--query:\n\n" + Sql_text);
        }
        return RESULT;
    }
    
    public static bool DB_Open(int Handle, string Sql_text)
    {
        bool RESULT = false;
        try
        {
            NATIVE_DB db = All_db[Handle];
            db.Sql = db.S_c.CreateCommand();
            
            if (db.Level_transaction >= 0)
            {
            	db.Sql.Transaction = db.All_transactions[db.Level_transaction];
            }
            
            db.Sql.CommandText = Sql_text;
            db.D_r = db.Sql.ExecuteReader();
            if (db.D_r.HasRows)
                RESULT = db.D_r.Read();
        }
        catch(Exception E)
        {
            AL4_system.Add_error_descr(E.GetType().Name + ": " + E.Message 
            + "\n--query:\n\n" + Sql_text);
            RESULT = false;
        }
        return RESULT;
    }
    
    public static void DB_Close(int Handle)
    {
        try
        {
            NATIVE_DB db = All_db[Handle];
            if (db.D_r != null)
            {
               db.D_r.Close();
               db.D_r = null;
            }
        }
        catch(Exception E)
        {
            AL4_system.Any_exception(E);
        }
    }
    
    public static bool DB_Next(int Handle)
    {
        bool RESULT = false;
        try
        {
            NATIVE_DB db = All_db[Handle];
            if (db.D_r == null) return false;
            RESULT = db.D_r.Read();
        }
        catch(Exception E)
        {
            AL4_system.Any_exception(E);
            RESULT = false;
        }
        return RESULT;
    }
    
    public static int DB_Count_fields(int Handle)
    {
        int RESULT = 0;
        try
        {
            NATIVE_DB db = All_db[Handle];
            if (db.D_r == null) return 0;
            RESULT = db.D_r.FieldCount;
        }
        catch(Exception E)
        {
            AL4_system.Any_exception(E);
            RESULT = 0;
        }
        return RESULT;
    }
    
    public static string DB_Field_name_by_index(int Handle, int Indx)
    {
        string RESULT = "";
        try
        {
            NATIVE_DB db = All_db[Handle];
            if (db.D_r == null) return "";
            if (Indx >= 0 && Indx < db.D_r.FieldCount)
                RESULT = db.D_r.GetName(Indx);
        }
        catch(Exception E)
        {
            //AL4_system.Any_exception(E);
            RESULT = "";
        }
        return RESULT;
    }
    
    public static int DB_Integer(int Handle, int Indx)
    {
        int RESULT = 0;
        try
        {
            NATIVE_DB db = All_db[Handle];
            if (db.D_r == null) return RESULT;
            if (Indx >= 0 && Indx < db.D_r.FieldCount)
            {
                //Type t = db.D_r.GetFieldType(Indx);
                if (db.D_r.IsDBNull(Indx)) return 0;
                Object v = db.D_r.GetValue(Indx);
                RESULT = Convert.ToInt32(v);
            }
        }
        catch(Exception E)
        {
            //AL4_system.Any_exception(E);
            RESULT = 0;
        }
        return RESULT;
    }
    
    public static double DB_Real(int Handle, int Indx)
    {
        double RESULT = 0;
        try
        {
            NATIVE_DB db = All_db[Handle];
            if (db.D_r == null) return RESULT;
            if (Indx >= 0 && Indx < db.D_r.FieldCount)
            {
                if (db.D_r.IsDBNull(Indx)) return RESULT;
                Object v = db.D_r.GetValue(Indx);
                RESULT = Convert.ToDouble(v);
            }
        }
        catch(Exception E)
        {
            //AL4_system.Any_exception(E);
            RESULT = 0;
        }
        return RESULT;
    }
    
    public static void DB_Id(int Handle, int Indx, ArrayInt Value)
    {
        try
        {
            NATIVE_DB db = All_db[Handle];
            if (db.D_r == null) return;
            if (Indx >= 0 && Indx < db.D_r.FieldCount)
            {
                if (db.D_r.IsDBNull(Indx)) return;
                Object v = db.D_r.GetValue(Indx);
                long x = Convert.ToInt64(v);
                Value.set_int(0, (int)x);
                Value.set_int(1, (int)(x >> 32));
            }
        }
        catch(Exception E)
        {
            //AL4_system.Any_exception(E);
        }
    }
    
    public static double DB_Date_time(int Handle, int Indx)
    {
        double RESULT = DateTime.MinValue.ToOADate();
        try
        {
            NATIVE_DB db = All_db[Handle];
            if (db.D_r == null) return RESULT;
            if (db.D_r.IsDBNull(Indx)) return RESULT;
            if (Indx >= 0 && Indx < db.D_r.FieldCount)
            {
                Object v = db.D_r.GetValue(Indx);
                RESULT = Convert.ToDateTime(v).ToOADate() * 24.0 * 3600000;
            }
        }
        catch(Exception E)
        {
            //AL4_system.Any_exception(E);
        }
        return RESULT;
    }
    
    public static bool DB_Boolean(int Handle, int Indx)
    {
        bool RESULT = false;
        try
        {
            NATIVE_DB db = All_db[Handle];
            if (db.D_r == null) return RESULT;
            if (Indx >= 0 && Indx < db.D_r.FieldCount)
            {
                if (db.D_r.IsDBNull(Indx)) return RESULT;
                Object v = db.D_r.GetValue(Indx);
                RESULT = Convert.ToBoolean(v);
            }
        }
        catch(Exception E)
        {
            //AL4_system.Any_exception(E);
        }
        return RESULT;
    }
    
    public static bool DB_Is_null(int Handle, int Indx)
    {
        bool RESULT = true;
        try
        {
            NATIVE_DB db = All_db[Handle];
            if (db.D_r == null) return RESULT;
            if (Indx >= 0 && Indx < db.D_r.FieldCount)
            {
                RESULT = db.D_r.IsDBNull(Indx);
            }
        }
        catch(Exception E)
        {
            //AL4_system.Any_exception(E);
        }
        return RESULT;
    }
    
    public static string DB_String(int Handle, int Indx)
    {
        string RESULT = "";
        try
        {
            NATIVE_DB db = All_db[Handle];
            if (db.D_r == null) return RESULT;
            if (Indx >= 0 && Indx < db.D_r.FieldCount)
            {
                if (db.D_r.IsDBNull(Indx)) return RESULT;
                Object v = db.D_r.GetValue(Indx);
                RESULT = Convert.ToString(v);
            }
        }
        catch(Exception E)
        {
            //AL4_system.Any_exception(E);
        }
        return RESULT;
    }
    
    public static void DB_Setup_blob_param(int Handle, Ref_obj X_Blob,
            int Index_blob )
    {
        C_Blob B =  (C_Blob)X_Blob.Obj;
        BlobReader S = new BlobReader(B);
        try
        {
            NATIVE_DB db = All_db[Handle];
            //if (db.D_r == null) return;
            
            if (db.use_OleDb)
            {
                byte[] value_blob = new byte[S.Length];
                S.Read(value_blob, 0, (int)S.Length);
                S.Close();
                ((OleDbCommand)db.Sql).Parameters.Add("@blob", OleDbType.Binary
                ).Value = value_blob;
            }
            else
            {
                byte[] value_blob = new byte[S.Length];
                S.Read(value_blob, 0, (int)S.Length);
                S.Close();
                ((SqlCommand)db.Sql).Parameters.Add("@blob", SqlDbType.Binary,
                    -1).Value = value_blob;
            }
        }
        catch(Exception E)
        {
            AL4_system.Any_exception(E);
        }
    }
    
/*
    
CONST STR:
    NATIVE_DB_import = ""
    
    NATIVE_DB_Create_connection = @
    "   RESULT = NATIVE_DB.DB_Create_connection(X_Connection, X_User, "
    "       X_Provider);"

    NATIVE_DB_Destroy_connection = @
    "   NATIVE_DB.DB_Destroy_connection((int)X_Handle);"

    NATIVE_DB_Connect = @
    "   RESULT = NATIVE_DB.DB_Connect((int)X_Handle, X_Password);"
    
    NATIVE_DB_Is_connected = @
    "   RESULT = NATIVE_DB.DB_Is_connected((int)X_Handle);"
    
    NATIVE_DB_Disconnect = @
    "   NATIVE_DB.DB_Disconnect((int)X_Handle);"

    NATIVE_DB_Begin_transaction = @
    "   RESULT = NATIVE_DB.DB_Begin_transaction((int)X_Handle);"

    NATIVE_DB_End_transaction = @
    "   NATIVE_DB.DB_End_transaction((int)X_Handle, (int)X_Transaction,"
    "       X_Commited);"

    NATIVE_DB_Commit_transaction = @
    ""

    NATIVE_DB_Rollback_transaction = @
    ""

    NATIVE_DB_Execute = @
    "   RESULT = NATIVE_DB.DB_Execute("
    "		(int)X_Handle, X_SQL, (DynAObjHard)X_Blobs);"

    NATIVE_DB_Open = @
    "   RESULT = !NATIVE_DB.DB_Open((int)X_Handle, X_SQL);"

    NATIVE_DB_Close = @
    "   NATIVE_DB.DB_Close((int)X_Handle);"

    NATIVE_DB_Next = @
    "   RESULT = NATIVE_DB.DB_Next((int)X_Handle);"

    NATIVE_DB_Count_fields = @
    "   RESULT = NATIVE_DB.DB_Count_fields((int)X_Handle);"

    NATIVE_DB_Field_by_index = @
    "   RESULT = NATIVE_DB.DB_Field_name_by_index((int)X_Handle, (int)X_Ind);"

    NATIVE_DB_Integer = @
    "   RESULT = NATIVE_DB.DB_Integer((int)X_Handle, (int)X_Ind);"

    NATIVE_DB_Real = @
    "   RESULT = NATIVE_DB.DB_Real((int)X_Handle, (int)X_Ind);"

    NATIVE_DB_Id = @
    "   NATIVE_DB.DB_Id((int)X_Handle, (int)X_Ind, X_Value);"

    NATIVE_DB_Date_time = @
    "   RESULT = NATIVE_DB.DB_Date_time((int)X_Handle, (int)X_Ind);"

    NATIVE_DB_Boolean = @
    "   RESULT = NATIVE_DB.DB_Boolean((int)X_Handle, (int)X_Ind);"

    NATIVE_DB_Is_null = @
    "   RESULT = NATIVE_DB.DB_Is_null((int)X_Handle, (int)X_Ind);"

    NATIVE_DB_String = @
    "   RESULT = NATIVE_DB.DB_String((int)X_Handle, (int)X_Ind);"
    
    .
        
*/

}

public class BlobReader : Stream
{
    C_Blob CBlob;
    
    public BlobReader(C_Blob CB_source)
    {
        CBlob = CB_source;
    }
    
    public override long Length
    {
        get 
        { 
            C_Stream C_S = (C_Stream)CBlob.F_Base_.Obj;
            C_Long_int.St_long siz = (C_Long_int.St_long)C_S.Do.M_Size().Obj;
            int result = (int)siz.f_Lo; // (long);
            siz.hard_link.Ref_dec_hard();
            return result;
        }
    }
    
    public override long Position
    {
        get 
        { 
            C_Stream C_S = (C_Stream)CBlob.F_Base_.Obj;
            C_Long_int.St_long pos = (C_Long_int.St_long)C_S.Do.M_Position().Obj; 
            int result = (int)pos.f_Lo;
            pos.hard_link.Ref_dec_hard();
            return result;
        }
        set
        {
            C_Stream C_S = (C_Stream)CBlob.F_Base_.Obj;
            C_Long_int.St_long new_pos = new C_Long_int.St_long();
            new_pos.f_Lo = (int)value; 
            C_S.Do.M_Set_pos(new_pos.hard_link, 0);
            new_pos.hard_link.Ref_dec_hard();
        }
    }
    
    public override void SetLength(long Value)
    { }
    
    public override bool CanRead
    {
        get { return true; }
    }
    
    public override int Read(byte[] buffer, int offset, int count)
    {
        C_Stream C_S = (C_Stream)CBlob.F_Base_.Obj;
        FixAByte_OnArray dest1 = new FixAByte_OnArray(buffer);
        FixAByte dest2 = new FixAByte(dest1, offset, count);
        return (int)C_S.Do.M_Read_bytes(dest2);
    }
    
    public override bool CanWrite
    {
        get { return false; }
    }
    
    public override void Write(byte[] buffer, int offset, int count)
    {  }
    
    public override void Flush()
    {  }
    
    public override bool CanSeek
    {
        get
        {
            return true;
        }
    }
    
    public override long Seek(long offset, SeekOrigin origin)
    {
        C_Stream C_S = (C_Stream)CBlob.F_Base_.Obj;
        byte method = 0;
        switch (origin)
        {
        case SeekOrigin.Begin:  method = 0; break;
        case SeekOrigin.Current:method = 1; break;
        case SeekOrigin.End:    method = 2; break;
        }
        C_Long_int.St_long off_to = new C_Long_int.St_long();
        off_to.f_Lo = (int)offset;
        C_S.Do.M_Set_pos(off_to.hard_link, method);
        off_to.hard_link.Ref_dec_hard();
        
        Ref_obj new_pos = C_S.Do.M_Position();
        int result = (int)((C_Long_int.St_long)new_pos.Obj).f_Lo;
        new_pos.Ref_dec_hard();
        return result;
    }
    
    public override void Close()
    {
        C_Stream C_S = (C_Stream)CBlob.F_Base_.Obj;
        C_S.Do.M_Close();
    }
}

/*
END
*/

