/*
 * Copyright (C) 2015 by Multi-Tech Systems
 *
 * This file is part of libmts-io.
 *
 * libmts-io 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.
 *
 * libmts-io 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 libmts-io.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

/*! 
 \file MTS_IO_SerialConnection.h
 \brief A brief description 
 \date Jan 15, 2013
 \author sgodinez

 A more elaborate description
*/

#ifndef MTS_IO_SERIALCONNECTION_H_
#define MTS_IO_SERIALCONNECTION_H_

#include <mts/MTS_IO_Connection.h>
#include <mts/MTS_IO_LockFile.h>
#include <sys/ioctl.h>
#include <termios.h>

namespace MTS {
    namespace IO {

        class SerialConnection : public Connection {

            public:

                enum ETYPE {
                    RS232,
                    RS422,
                    RS485
                };

                enum EPARITY {
                    OFF,
                    ODD,
                    EVEN
                };

                enum EDATABITS {
                    B5,
                    B6,
                    B7,
                    B8
                };

                enum ESTOPBITS {
                    B1,
                    B2
                };

                enum IOCTL {
                	LE = TIOCM_LE,
                	DTR = TIOCM_DTR,
                	RTS = TIOCM_RTS,
                	ST = TIOCM_ST,
                	SR = TIOCM_SR,
                	CTS = TIOCM_CTS,
                	CAR = TIOCM_CAR,
                	CD = TIOCM_CD,
                	RNG = TIOCM_RNG,
                	RI = TIOCM_RI,
                	DSR = TIOCM_DSR
                };

                enum FLOW_CONTROL {
                	NONE,
                	RTS_CTS
                };

                class Builder {
                    public:
                        Builder(const std::string& sPortName);

                        Builder& type(const ETYPE& eType);
                        Builder& rs232();
                        Builder& rs422();
                        Builder& rs485();

                        Builder& parity(const EPARITY& eParity);
                        Builder& parityOff();
                        Builder& parityOdd();
                        Builder& parityEven();

                        Builder& dataBits(const EDATABITS& eDataLength);
                        Builder& fiveDataBits();
                        Builder& sixDataBits();
                        Builder& sevenDataBits();
                        Builder& eightDataBits();

                        Builder& stopBits(const ESTOPBITS& eStopBits);
                        Builder& oneStopBit();
                        Builder& twoStopBits();

                        Builder& useLockFile(bool enabled = true);
                        Builder& flowControl(const FLOW_CONTROL& eFlowControl);
                        Builder& baudRate(uint32_t iBaud);

                        Builder& build();

                        const std::string&  getPortName() const;
                        const uint32_t&     getBaudRate() const;
                        ETYPE               getType() const;
                        EPARITY             getParity() const;
                        EDATABITS           getDataBits() const;
                        ESTOPBITS           getStopBits() const;
                        FLOW_CONTROL		getFlowControl() const;
                        std::string         getTypeAsString() const;
                        bool                isUsingLockFile() const;
                        bool                isBuilt() const;

                    private:
                        std::string m_sPortName;
                        uint32_t m_iBaudRate;
                        ETYPE m_eType;
                        EPARITY m_eParity;
                        EDATABITS m_eDataBits;
                        ESTOPBITS m_eStopBits;
                        FLOW_CONTROL m_eFlowControl;
                        bool m_bLockFile;
                        bool m_bBuilt;
                };

                SerialConnection(const Builder& oBuilder);
                virtual ~SerialConnection();

                const std::string& getPortName() const;
                uint32_t getBaudRate() const;

                void flush();
                void drain();
            protected:
                virtual int getFileDescriptor();

            private:
                const std::string m_sPortName;
                uint32_t m_iBaudRate;
                ETYPE m_eType;
                EPARITY m_eParity;
                EDATABITS m_eDataBits;
                ESTOPBITS m_eStopBits;
				FLOW_CONTROL m_eFlowControl;
                AutoPtr<LockFile> m_apLockFile;

                AutoPtr<Lock> m_apHandleLock;
#ifdef WIN32
                HANDLE m_iHandle;
#else
                int m_iHandle;
                termios m_stPrevOptions;
#endif

                virtual bool doOpen(const int32_t& timeoutMillis);
                virtual void doClose();
                virtual int doRead(char* pBuffer, const uint32_t& iSize, int32_t& timeoutMillis);
                virtual int doWrite(const char* pBuffer, const uint32_t& iSize, int32_t& timeoutMillis);

                void cleanup();
                void printPortSetting(const termios *options);
                const char* humanSpeed(speed_t speed);
        };
    }
}


#endif /* MTS_IO_SERIALCONNECTION_H_ */