/*
https://github.com/peterix/dfhack
Copyright (c) 2009-2012 Petr Mrázek (peterix@gmail.com)

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.

Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.

2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.

3. This notice may not be removed or altered from any source
distribution.
*/

#pragma once
#include "Pragma.h"
#include "Export.h"
#include "ColorText.h"
#include <deque>
#include <fstream>
#include <assert.h>
#include <iostream>
#include <string>
namespace tthread
{
    class mutex;
    class recursive_mutex;
    class condition_variable;
    class thread;
}
namespace  DFHack
{
    class CommandHistory
    {
    public:
        CommandHistory(std::size_t capacity = 100)
        {
            this->capacity = capacity;
        }
        bool load (const char * filename)
        {
            std::string reader;
            std::ifstream infile(filename);
            if(infile.bad())
                return false;
            std::string s;
            while(std::getline(infile, s))
            {
                if(s.empty())
                    continue;
                history.push_back(s);
            }
            return true;
        }
        bool save (const char * filename)
        {
            if (!history.size())
                return true;
            std::ofstream outfile (filename);
            //fprintf(stderr,"Save: Initialized stream\n");
            if(outfile.bad())
                return false;
            //fprintf(stderr,"Save: Iterating...\n");
            for(auto iter = history.begin();iter < history.end(); iter++)
            {
                //fprintf(stderr,"Save: Dumping %s\n",(*iter).c_str());
                outfile << *iter << std::endl;
                //fprintf(stderr,"Save: Flushing\n");
                outfile.flush();
            }
            //fprintf(stderr,"Save: Closing\n");
            outfile.close();
            //fprintf(stderr,"Save: Done\n");
            return true;
        }
        /// add a command to the history
        void add(const std::string& command)
        {
            // if current command = last in history -> do not add. Always add if history is empty.
            if(!history.empty() && history.front() == command)
                return;
            history.push_front(command);
            if(history.size() > capacity)
                history.pop_back();
        }
        /// clear the command history
        void clear()
        {
            history.clear();
        }
        /// get current history size
        std::size_t size()
        {
            return history.size();
        }
        /// get pointer to a particular history item
        std::string & operator[](std::size_t index)
        {
            assert(index < history.size());
            return history[index];
        }
        void remove( void )
        {
            history.pop_front();
        }
    private:
        std::size_t capacity;
        std::deque <std::string> history;
    };

    class Private;
    class DFHACK_EXPORT Console : public color_ostream
    {
    protected:
        virtual void begin_batch();
        virtual void add_text(color_value color, const std::string &text);
        virtual void end_batch();

        virtual void flush_proxy();

    public:
        ///ctor, NOT thread-safe
        Console();
        ///dtor, NOT thread-safe
        ~Console();
        /// initialize the console. NOT thread-safe
        bool init( bool sharing );
        /// shutdown the console. NOT thread-safe
        bool shutdown( void );

        /// Clear the console, along with its scrollback
        void clear();
        /// Position cursor at x,y. 1,1 = top left corner
        void gotoxy(int x, int y);
        /// Enable or disable the caret/cursor
        void cursor(bool enable = true);
        /// Waits given number of milliseconds before continuing.
        void msleep(unsigned int msec);
        /// get the current number of columns
        int  get_columns(void);
        /// get the current number of rows
        int  get_rows(void);
        /// beep. maybe?
        //void beep (void);
        /// A simple line edit (raw mode)
        int lineedit(const std::string& prompt, std::string& output, CommandHistory & history );
        bool isInited (void) { return inited; };

        bool is_console() { return true; }

        bool hide();
        bool show();
    private:
        Private * d;
        tthread::recursive_mutex * wlock;
        bool inited;
    };
}
