## My problem is I need to know ##

 - is my code in my CRUD functions structured well and effectively?  I plan to implement CRUD for Locations entity too. hopefully without redundant code.
 - you see how one CRUD function in the program class calls the other CRUD function in the DataAccess Class?  I"m trying to set it up so that i can control which entity gets edited or read in the control class, and access it in the dataAccess class.  Is this bad logic?

Info on classes
-------

 - **Program** - I'm trying to put all controlling logic here
 - **DataAccess** - I'm trying to put my Data-accessing logic here, away from everything else.  
 - **UserInterface** - I'm trying to put my Interface logic here, away from everything else.  Such as the way information gets displayed to the user, the way info gets received from user.
 - **InputValidation** - I want to put all logic that validates user input here, ranging from Type validation to input range validation.
 - **ServiceManager** - class that has a method that checks to see if SQL server is running, before doing LINQ calls to DataBase.
 - **DbResult** - a repository wrapper class containing a string message, and a boolean.  Used to report failure/success results with a message like "success!" or whatever exception.ToString() prints.  *I am thinking this class should be removed*?
 - **Man** - *auto-generated class by entity framework.*
 - **Location** - *auto-generated class by entity framework.* I plan to implement this class in my CRUD functions as soon as I can get working clean logic for the CRUD functions that handle the Man class.  And hopefully `Man` & `Location` can share the same CRUD functions.

## Notes ##

 - I'd like to enable CRUD functions to handle more than one entity class, without copying and pasting 4 CRUD functions for each new entity.
 - I'm considering removing DbResult, but not sure how to without keeping Data-Accessing logic separate  from User Interface logic.  My thought was to pass whatever message needed to be shown to the user, to the Interface class for it to be displayed. 

## Program Class ##

    class Program
    {
        static private UserInterface _MyUI; 
        static void Main(string[] args)
        {
            DbResult resultSQLRunning;
            ServiceManager mySM = new ServiceManager();
            _MyUI = new UserInterface();
            
            resultSQLRunning = mySM.SQLRunning();

            _MyUI.DisplayMessage(resultSQLRunning.Message);

            if (resultSQLRunning.bSuccess)
            {
                using (TestDatabaseEntities myDB = new TestDatabaseEntities())
                {
                    DataAccess myDA = new DataAccess(myDB);
                    DbResult myResult = myDA.DatabaseExists();
                    _MyUI.DisplayMessage(myResult.Message);
                }
                do
                {
                    DecideFromMenuChoice(_MyUI.GetUserAction());
                } while (_MyUI._MyMenuStage != UserInterface.MenuStage.MENU_EXIT);
            }
            Console.ReadLine(); // press any key to exit, basically.
        }
        
        static private void DecideFromMenuChoice(int choice)
        {
            if (_MyUI._MyMenuStage == UserInterface.MenuStage.MENU_CRUD)
            {
                switch (choice)
                {
                    case 1: DoCreate(); break;
                    case 2: DoRead(); break;
                    case 3: DoUpdate(); break;
                    case 4: DoDelete(); break;
                    default:
                        break;
                }
            }
            /* else if (_MyUI._MyMenuStage == UserInterface.MenuStage.MENU_TABLE)
            {
                switch (choice)
                {
                    // not sure what to do here, somehow select a table to be used in CRUD functions? 
                    // do i need to call more CRUD functions for each new table I add?
                }
            }*/
        }
        // ============================
        // CRUD FUNCTIONS
        // ============================
        static private void DoCreate()
        {
 	    int myID;
            bool isValidID;
            var dbEntities = new TestDatabaseEntities();
            string newName;

            DataAccess MyDA = new DataAccess(dbEntities);
            DbResult CreationResult, SaveResult;

            do
            {
                isValidID = _MyUI.GetValidInput<int>("Enter ID: ", int.TryParse, out myID);
            }
            while (!isValidID);

            newName = _MyUI.GetInput<string>("Enter Name:", x => x.Trim());

            CreationResult = MyDA.Create(new Man() {ManID = myID, Name = newName });
            _MyUI.DisplayMessage(CreationResult.Message);

            if (!CreationResult.bSuccess)
                return;

            SaveResult = MyDA.SaveChanges();
            _MyUI.DisplayMessage(SaveResult.Message);
        }
        static private void DoRead()
        {
            var dbEntities = new TestDatabaseEntities();
            DataAccess myDA = new DataAccess(dbEntities);
            string [,] records;
            DbResult readResult;

            var query = from person in dbEntities.Men
                        where true
                        select person;
            readResult = myDA.Read(query, out records);
            if (readResult.bSuccess)
            {
                _MyUI.DisplayRecords(records);
            }
            if (!readResult.bSuccess)
                _MyUI.DisplayMessage(readResult.Message);
        }
        static private void DoUpdate()
        {
            /* The code in this DoUpdate function is "simplified" and "cleaner" 
             * than the commented block below, I'm told. is it?*/
            int myID = _MyUI.GetInput<int>("Enter ID to update: ", int.Parse);
            string newName = _MyUI.GetInput<string>("Enter new name: ", x => x.Trim());

            try
            {
                using (var dbEntities = new TestDatabaseEntities())
                {
                    //TODO: If ManID is unique then we can use FirstOrDefault here.
                    var allMatchingMen =
                        from person in dbEntities.Men
                        where person.ManID == myID
                        select person;

                    foreach (var man in allMatchingMen)
                        man.Name = newName;

                    dbEntities.SaveChanges();
                    _MyUI.DisplayMessage("Record(s) updated");
                }
            }
            /*catch (OptimisticConcurrencyException ex)
            {
                //TODO: add auto-retry logic
                _MyUI.DisplayMessage("Someone updated the record, let's retry");
            }*/
            catch (Exception ex)
            {
                _MyUI.DisplayMessage("Something went wrong, could not update");
            }
        } 
        /*{
            int myID;
            var dbEntities = new TestDatabaseEntities();
            string newName = "";
            DataAccess MyDA = new DataAccess(dbEntities);
            DbResult updateResult, saveResult;

            myID = _MyUI.GetInput<int>("Enter ID to update: ", int.Parse);
            newName = _MyUI.GetInput<string>("Enter new name: ", x => x.Trim());

            var query =
                from person in dbEntities.Men
                where person.ManID == myID
                select person;

            updateResult = myDA.Update(query, new Man() { ManID = myID, Name = sNewName });
            _MyUI.DisplayMessage(updateResult.Message);

            if (!UpdateResult.bSuccess)
                return;

            SaveResult = myDA.SaveChanges();
            _MyUI.DisplayMessage(saveResult.Message);
        }*/
        static private void DoDelete() 
        {
            int myID;
            bool isValidInput;
            var dbEntities = new TestDatabaseEntities();
            DataAccess myDA = new DataAccess(dbEntities);
            DbResult deleteResult, saveResult;

            do
            {
                isValidInput = _MyUI.GetValidInput<int>("Enter ID to delete: ", int.TryParse, out myID);
            } while (!isValidInput);

            var Query =
                from person in dbEntities.Men
                where person.ManID == myID
                select person;

            deleteResult = myDA.Delete(Query);
            _MyUI.DisplayMessage(deleteResult.Message);

            if (!deleteResult.bSuccess)
                return;

            saveResult = myDA.SaveChanges();
            _MyUI.DisplayMessage(saveResult.Message);
        }
    }

## DataAccess Class ##

    public class DataAccess
    {
        private readonly TestDatabaseEntities _MyDBEntities;

        public DataAccess(TestDatabaseEntities entities)
        {
            _MyDBEntities = entities;
        }


        public DbResult DatabaseExists()
        {
            DbResult myResult;

            if (_MyDBEntities.Database.Exists())
                myResult = DbResult.Success("Database Found");
            else
                myResult = DbResult.Failed("Database Not Found");

            return myResult;
        }

        // ============================
        // CRUD FUNCTIONS for MAN TABLE
        // ============================

        public DbResult Create(Man M)
        {
            DbResult dbResult;

            try
            {
                _MyDBEntities.Men.Add(new Man { ManID = M.ManID, Name = M.Name });
                dbResult = DbResult.Success("Record created");
            }
            catch (Exception e)
            {
                dbResult = DbResult.Failed(e.ToString());   
            }            
            return dbResult;
        }

        public DbResult Update(IQueryable<Man> myQuery, Man man)
        {
            DbResult dbResult;

            try
            {
                foreach (Man M in myQuery)
                {
                    M.Name = man.Name;
                }
                dbResult = DbResult.Success("Record updated");
            }
            catch (Exception e)
            {
                dbResult = DbResult.Failed(e.ToString());   
            }

            return dbResult;
        }

        public DbResult Delete(IQueryable myQuery)
        {
            DbResult dbResult;

            try
            {
                foreach (Man M in myQuery)
                {
                    _MyDBEntities.Men.Remove(M);
                }
                dbResult = DbResult.Success("Record deleted");
            }
            catch (Exception e)
            {
                dbResult = DbResult.Failed(e.ToString());                
            }

            return dbResult;
        }

        public DbResult Read(IQueryable myQuery, out string[,] records)
        {
            DbResult dbResult;
            records = null;
            try
            {
                List<Man> men = myQuery.OfType<Man>().ToList();
                records = new string[men.Count, 2];
                for (int i = 0; i < men.Count; i++)
                {
                    records[i, 0] = men[i].ManID.ToString();
                    records[i, 1] = men[i].Name;
                }
                dbResult = DbResult.Success("Read Success");
            }
            catch (Exception e)
            {
                dbResult = DbResult.Failed(e.ToString());
            }

            return dbResult;
        }

        // ============================
        // SAVECHANGES FUNCTION
        // ============================
        public DbResult SaveChanges()
        {
            DbResult dbResult;
            try
            {
                _MyDBEntities.SaveChanges();
                dbResult = DbResult.Success("Saved successfully");
            }
            catch (Exception e)
            {
                dbResult = DbResult.Failed(e.ToString());
            }

            return dbResult;
        }
    }

## UserInterface Class ##

    public class UserInterface
    {
        public enum MenuStage
        {
            MENU_EXIT,
            MENU_CRUD,
            MENU_TableSelect
        }
        public MenuStage _MyMenuStage{ get; private set; }

        public UserInterface()
        {
            _MyMenuStage = MenuStage.MENU_CRUD;
        }
        /// <summary>
        /// Prompts user for input with given message, and converts input to type T
        /// </summary>
        /// <typeparam name="T">Value type to convert to, and return</typeparam>
        /// <param name="message">Message to be printed to console</param>
        /// <param name="transform">The type conversion function to use on user's input</param>
        /// <returns>Type T</returns>
        public T GetInput<T>(string message, Converter<string, T> transform)
        {
            DisplayPrompt(message);
            return transform(Console.ReadLine());
        }
        /// <summary>
        /// Asks the user for valid input
        /// </summary>
        /// <typeparam name="T">The type of result to return as out parameter</typeparam>
        /// <param name="message">The message to prompt the user with</param>
        /// <param name="errorMessage">The message to Display to user with if input is invalid</param>
        /// <param name="typeValidator">The TryParse function to use to test the input.</param>
        /// <returns>True if input is valid as per function given to TypeValidator, Result as type T</returns>
        public bool GetValidInput<T>(string message, InputValidation.TryParse<T> typeValidator, out T result, int upper = -1, int lower = -1)
        {
            InputValidation myInputValidator = new InputValidation();
            bool isValid = false;
            bool shouldTestRange = (upper != -1 && lower != -1);
            string input;
            
            input = GetInput(message, x => (x.Trim()));
            
            isValid = myInputValidator.ValidateInputType(input, typeValidator, out result);

            if (!isValid)
            {
                DisplayMessage("Error, invalid input type entered, type required is " + typeof(T).ToString());
                return false;
            }

            if (shouldTestRange)
                isValid = myInputValidator.ValidateInputRange(ref result, lower, upper);

            if (!isValid)
            {
                DisplayMessage("Error, input is out of range.  Range: " + lower.ToString() + " - " + upper.ToString());
                return false;
            }

            return isValid;
        }

        public void DisplayMessage(string message)
        {
            Console.WriteLine(message);
        }
        public void DisplayPrompt(string message)
        {
            Console.Write(message);
        }
        public void DisplayRecords(string[,] message)
        {
            if (message == null)
                return;

            DisplayDivider();
            for (int i = 0; i < message.GetLength(0); i++)
            {
                for (int j = 0; j < message.GetLength(1); j++)
                {
                    Console.Write(message[i, j] + " ");
                }
                Console.Write("\n"); 
            }
            DisplayDivider();
        }
        public void DisplayMenuOptions(string[] items)
        { 
            byte index = 0;
            DisplayDivider('~');
            Console.WriteLine("Select an action from menu");
            foreach (string s in items)
            {
                Console.WriteLine(index++ + ") " + s);
            }
            DisplayDivider('~');
        }
        public void DisplayDivider(char myChar = '|')
        {
            String myDivider = new String(myChar, 30);
            
            DisplayMessage(myDivider);
        }

        public int GetUserAction()
        {
            string[] menuOptions;
            int choice = -1;

            //TODO: implement logic that Chooses which MenuStage we're at.

            menuOptions = DecideMenuOptions();
            DisplayMenuOptions(menuOptions);

            choice = GetInputFromRange(0, menuOptions.Length - 1);

            if (choice == 0)
            {
                _MyMenuStage = MenuStage.MENU_EXIT;
            }

            return choice;
        }

        private int GetInputFromRange(int lowerBound, int upperBound)
        {
            int choice;
            bool isValid = false;

            do
            {
                isValid = (GetValidInput<int>("Enter choice> ", int.TryParse, out choice, lower: lowerBound, upper: upperBound));
            } while (!isValid);
            return choice;
        }

        /// <summary>
        /// Determines which menu options need to be displayed
        /// </summary>
        /// <returns>Menu options that need to be displayed</returns>
        private string[] DecideMenuOptions()
        {
            string[] menuCRUD = new string[] { "Exit", "Create", "Read", "Update", "Delete" };
            string[] menuTables = new string[] { "Quit", "Men", "Locations" };
            string[] myMenuChoices = null;
            
            if (_MyMenuStage == MenuStage.MENU_CRUD)
            {
                myMenuChoices = menuCRUD;
            }
            else if (_MyMenuStage == MenuStage.MENU_TableSelect)
            {
                myMenuChoices = menuTables;
            }

            return myMenuChoices;
        }
    }
## InputValidation Class ##

    public class InputValidation//<T> where T: class
    {
        /// <summary>
        /// Delegate that matches the signature of TryParse, method defined for all primitives.
        /// </summary>
        /// <typeparam name="T">Output type of This Delegate</typeparam>
        /// <param name="input">input for this Delegate to translate to type T</param>
        /// <param name="output">The translated variable to return via out parameter</param>
        /// <returns>Whether the Parse was successful or not, and output as output</returns>
        public delegate bool TryParse<T>(string sInput, out T output);
        public bool ValidateInputType<T>(string sInput, TryParse<T> TypeValidator, out T result)
        {
            return TypeValidator(sInput, out result);
        }
        public bool ValidateInputRange<T>(ref T result, int lower, int upper)
        {
            // How can I use relational operators like > < = on T? without forcing T result to an int?
            return isValidRange(int.Parse(result.ToString()), lower, upper);
        }
        public bool isValidRange(int item, int Lower, int Upper)
        {
            return (Lower <= item && item <= Upper);
        }
    }

## ServiceManager Class ##

    public class ServiceManager
    {
        public DbResult SQLRunning()
        {
            DbResult myResult;
            ServiceController sc = new ServiceController("SQL Server (SQLEXPRESS)");

            if (sc.Status == ServiceControllerStatus.Running)
                myResult = DbResult.Success("SQL Server is running");
            else
                myResult = DbResult.Failed("SQL Server is NOT running.");

            return myResult;
        }
    }

## DbResult (wrapper class) ##

    public class DbResult
    {
        public bool bSuccess { get; private set; }
        public String Message { get; private set; }

        private DbResult(bool success, string message)
        {
            this.bSuccess = success;
            this.Message = message;
        }

        public static DbResult Failed(string message)
        {
            return new DbResult(false, message);
        }

        public static DbResult Success(string message)
        {
            return new DbResult(true, message);
        }
    }

## Man Class ##

    public partial class Man
    {
        public Man()
        {
            this.Locations = new HashSet<Location>();
        }
    
        public int ManID { get; set; }
        public string Name { get; set; }
    
        public virtual ICollection<Location> Locations { get; set; }
    }

## Location Class ##

    public partial class Location
    {
        public Location()
        {
            this.Men = new HashSet<Man>();
        }
    
        public int PlaceID { get; set; }
        public string Place { get; set; }
    
        public virtual ICollection<Man> Men { get; set; }
    }

## **UPDATE:** ##
11/20/12 9:01 CST: Improved seperation of logic in UserInterface class and Program Class. At least I think so.
11/21/12 6:46 CST: Improved UserInterface class slightly.