using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Collections;

namespace Sdaleo
{
    /// <summary>
    /// Used by Callers to determine DB Operation Outcome
    /// </summary>
    public enum DBRetValEnum
    {
        VALUE_FETCHED,
        VALUE_NOTFETCHED,
        NQ_NO_ROWS_AFFECTED,
        NQ_ONE_ROW_AFFECTED,
        NQ_MULTIPLE_ROWS_AFFECTED,
        FAILED
    }

    /// <summary>
    /// Our Database RetVal Class that DB Callers use to get Values
    /// </summary>
    public class DBRetVal : DBError
    {
        public DBRetValEnum Result { get; private set; }
            
        // * Return Values from various DB Calls *
        private DataTable RetVal_datatable { get; set; }
        private String RetVal_string { get; set; }
        private int RetVal_int { get; set; } // for NQ calls

        // * Internal Mode *
        private enum Mode
        {
            MODE_INIT,
            MODE_VALUE_DT,
            MODE_VALUE_STR,
            MODE_NQ_INT,
        }
        private Mode _Mode = Mode.MODE_INIT;

        #region Construction

        /// <summary>
        /// Initialize DBRetVal
        /// </summary>
        public DBRetVal()
                : base()
        {
             _Mode = Mode.MODE_INIT;
             Result = DBRetValEnum.FAILED;
             RetVal_datatable = null;
             RetVal_string = String.Empty;
             RetVal_int = Int32.MinValue;
        }        

        /// <summary>
        /// Initialize DBRetVal with Error Info
        /// </summary>
        public DBRetVal(int nError, string ErrorMsg, ICollection Errors)
                : base(nError, ErrorMsg, Errors)
        {
            _Mode = Mode.MODE_INIT;
            Result = DBRetValEnum.FAILED;
            RetVal_datatable = null;
            RetVal_string = String.Empty;
            RetVal_int = Int32.MinValue;
        }

        /// <summary>
        /// Initialize DBRetVal with SDaleo Default Error Info
        /// </summary>
        public DBRetVal(string ErrorMsg)
            : base(ErrorMsg)
        {
            _Mode = Mode.MODE_INIT;
            Result = DBRetValEnum.FAILED;
            RetVal_datatable = null;
            RetVal_string = String.Empty;
            RetVal_int = Int32.MinValue;
        }

        #endregion

        #region Validator

        /// <summary>
        /// Returns True if the Return value of this object is valid
        /// </summary>
        public bool IsValid
        {
            get
            {
                bool bIsValid = false;
                switch (_Mode)
                {
                    case Mode.MODE_INIT:
                        bIsValid = false;
                        break;

                    case Mode.MODE_NQ_INT:
                        bIsValid = (RetVal_int != Int32.MinValue) && (Result != DBRetValEnum.FAILED) && (Result != DBRetValEnum.VALUE_NOTFETCHED);
                        break;

                    case Mode.MODE_VALUE_DT:
                        bIsValid = (RetVal_datatable != null) && (Result != DBRetValEnum.FAILED) && (Result != DBRetValEnum.VALUE_NOTFETCHED);
                        break;

                    case Mode.MODE_VALUE_STR:
                        bIsValid = !String.IsNullOrEmpty(RetVal_string) && (Result != DBRetValEnum.FAILED) && (Result != DBRetValEnum.VALUE_NOTFETCHED);
                        break;

                    default:
                        bIsValid = false;
                        break;
                }

                // Double-check that there are no errors in DBError as well,
                if (bIsValid)
                    bIsValid = !ErrorOccured;
                return bIsValid;
            }
        }

        #endregion

        #region Getters

        /// <summary>
        /// Get the DataTable Return Value
        /// </summary>
        /// <returns>valid datatable or throws Exception, if in invalid state</returns>
        public DataTable GetDataTableRetVal()
        {
            if (_Mode == Mode.MODE_VALUE_DT)
            {
                return RetVal_datatable;
            }
            else
            {
                throw new Exception(String.Format("Invalid State {0}. Can not call GetRetVal() for DataTable right now", _Mode.ToString()));
            }
        }

        /// <summary>
        /// Get the First Row of the DataTable Return Value
        /// </summary>
        /// <returns>valid datatable or throws Exception, if in invalid state</returns>
        public DataRow GetDataTableFirstRow()
        {
            if (_Mode == Mode.MODE_VALUE_DT)
            {
                return RetVal_datatable.Rows[0];
            }
            else
            {
                throw new Exception(String.Format("Invalid State {0}. Can not call GetRetVal() for DataTable right now", _Mode.ToString()));
            }
        }

        /// <summary>
        /// Get the Scalar/String Return Value
        /// </summary>
        /// <returns>valid string or throws Exception, if in invalid state</returns>
        public string GetScalarRetVal()
        {
            if (_Mode == Mode.MODE_VALUE_STR)
            {
                return RetVal_string;
            }
            else
            {
                throw new Exception(String.Format("Invalid State {0}. Can not call GetRetVal() for String right now", _Mode.ToString()));
            }
        }

        /// <summary>
        /// Get the NQ Return Value
        /// </summary>
        /// <returns>valid nRows or throws Exception, if in invalid state</returns>
        public int GetNonQueryRetVal()
        {
            if (_Mode == Mode.MODE_NQ_INT)
            {
                return RetVal_int;
            }
            else
            {
                throw new Exception(String.Format("Invalid State {0}. Can not call GetRetValNQ() right now", _Mode.ToString()));
            }
        }

        #endregion 

        #region Internal Setters

        /// <summary>
        /// Set the Return Value to a DataTable
        /// </summary>
        /// <param name="datatable">a valid DataTable</param>
        /// <param name="result">a result to pass out * can not be NQ enum *</param>
        internal void SetDataTableRetVal(DataTable datatable)
        {
            _Mode = Mode.MODE_VALUE_DT;
            if (datatable == null || (datatable.Rows.Count == 0))
            {
                Result = DBRetValEnum.VALUE_NOTFETCHED;
            }            
            else
            {
                Result = DBRetValEnum.VALUE_FETCHED;
                RetVal_datatable = datatable;
            }

            // Clear Others
            RetVal_string = String.Empty;
            RetVal_int = Int32.MinValue;
        }

        /// <summary>
        /// Set the Return Value to a String (pass in an object to be converted)
        /// </summary>
        /// <param name="o">a object that should be converted to a String</param>
        internal void SetScalarRetVal(object o)
        {
            _Mode = Mode.MODE_VALUE_STR;
            if (o == null || (o.ToString() == String.Empty))
            {
                Result = DBRetValEnum.VALUE_NOTFETCHED;
            }            
            else
            {
                RetVal_string = o.ToString();
                Result = DBRetValEnum.VALUE_FETCHED;
            }

            // Clear Others
            RetVal_datatable = null;
            RetVal_int = Int32.MinValue;
        }

        /// <summary>
        /// Set the Return Value for a NQ Query
        /// </summary>
        /// <param name="nRows">number of rows affected</param>
        internal void SetNonQueryRetVal(int nRows)
        {            
            _Mode = Mode.MODE_NQ_INT;
            RetVal_int = nRows;
            if (nRows <= 0)   
                Result = DBRetValEnum.NQ_NO_ROWS_AFFECTED;
            else if (nRows == 1)                
                Result = DBRetValEnum.NQ_ONE_ROW_AFFECTED;
            else                
                Result = DBRetValEnum.NQ_MULTIPLE_ROWS_AFFECTED;

            // Clear Others
            RetVal_datatable = null;
            RetVal_string = String.Empty;
        }

        #endregion
      
    }
}
