//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
// copyright            : (C) 2014 Eran Ifrah
// file name            : astyle_main.h
//
// -------------------------------------------------------------------------
// A
//              _____           _      _     _ _
//             /  __ \         | |    | |   (_) |
//             | /  \/ ___   __| | ___| |    _| |_ ___
//             | |    / _ \ / _  |/ _ \ |   | | __/ _ )
//             | \__/\ (_) | (_| |  __/ |___| | ||  __/
//              \____/\___/ \__,_|\___\_____/_|\__\___|
//
//                                                  F i l e
//
//    This program is free software; you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation; either version 2 of the License, or
//    (at your option) any later version.
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *   astyle_main.h
 *
 *   Copyright (C) 2006-2011 by Jim Pattee <jimp03@email.com>
 *   Copyright (C) 1998-2002 by Tal Davidson
 *   <http://www.gnu.org/licenses/lgpl-3.0.html>
 *
 *   This file is a part of Artistic Style - an indentation and
 *   reformatting tool for C, C++, C# and Java source files.
 *   <http://astyle.sourceforge.net>
 *
 *   Artistic Style 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 3 of the License, or
 *   (at your option) any later version.
 *
 *   Artistic Style 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 Artistic Style.  If not, see <http://www.gnu.org/licenses/>.
 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 */

#ifndef ASTYLE_MAIN_H
#define ASTYLE_MAIN_H

//----------------------------------------------------------------------------
// headers
//----------------------------------------------------------------------------

#include <sstream>
#include <ctime>
#include "astyle.h"

#if defined(_MSC_VER) || defined(__DMC__)
#include <sys/utime.h>
#include <sys/stat.h>
#else
#include <utime.h>
#include <sys/stat.h>
#endif // end compiler checks

#ifdef ASTYLE_JNI
#include <jni.h>
#ifndef ASTYLE_LIB // ASTYLE_LIB must be defined for ASTYLE_JNI
#define ASTYLE_LIB
#endif
#endif //  ASTYLE_JNI

// for console build only
#ifndef ASTYLE_LIB
#include "ASLocalizer.h"
#define _(a) localizer.settext(a)
#endif

// for G++ implementation of string.compare:
#if defined(__GNUC__) && __GNUC__ < 3
#error - Use GNU C compiler release 3 or higher
#endif

// for namespace problem in version 5.0
#if defined(_MSC_VER) && _MSC_VER < 1200 // check for V6.0
#error - Use Microsoft compiler version 6 or higher
#endif

// for mingw BOM, UTF-16, and Unicode functions
#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
#if(__MINGW32_MAJOR_VERSION > 3) || ((__MINGW32_MAJOR_VERSION == 3) && (__MINGW32_MINOR_VERSION < 16))
#error - Use MinGW compiler version 4 or higher
#endif
#endif

namespace astyle
{

//----------------------------------------------------------------------------
// ASStreamIterator class
// typename will be istringstream for GUI and istream otherwise
// ASSourceIterator is an abstract class defined in astyle.h
//----------------------------------------------------------------------------

template <typename T> class ASStreamIterator : public ASSourceIterator
{
public:
    bool checkForEmptyLine;

    // function declarations
    ASStreamIterator(T* in);
    virtual ~ASStreamIterator();
    bool getLineEndChange(int lineEndFormat) const;
    string nextLine(bool emptyLineWasDeleted);
    string peekNextLine();
    void peekReset();
    void saveLastInputLine();

private:
    ASStreamIterator(const ASStreamIterator& copy); // copy constructor not to be imlpemented
    ASStreamIterator& operator=(ASStreamIterator&); // assignment operator not to be implemented
    T* inStream;                                    // pointer to the input stream
    string buffer;                                  // current input line
    string prevBuffer;                              // previous input line
    int eolWindows;                                 // number of Windows line endings, CRLF
    int eolLinux;                                   // number of Linux line endings, LF
    int eolMacOld;                                  // number of old Mac line endings. CR
    char outputEOL[4];                              // next output end of line char
    streamoff peekStart;                            // starting position for peekNextLine
    bool prevLineDeleted;                           // the previous input line was deleted

public: // inline functions
    bool compareToInputBuffer(const string& nextLine_) const { return (nextLine_ == prevBuffer); }
    const char* getOutputEOL() const { return outputEOL; }
    bool hasMoreLines() const { return !inStream->eof(); }
};

//----------------------------------------------------------------------------
// ASOptions class for options processing
// used by both console and library builds
//----------------------------------------------------------------------------

class ASOptions
{
public:
    ASOptions(ASFormatter& formatterArg)
        : formatter(formatterArg)
    {
    }
    string getOptionErrors();
    void importOptions(istream& in, vector<string>& optionsVector);
    bool parseOptions(vector<string>& optionsVector, const string& errorInfo);

private:
    // variables
    ASFormatter& formatter;    // reference to the ASFormatter object
    stringstream optionErrors; // option error messages

    // functions
    ASOptions& operator=(ASOptions&); // not to be implemented
    string getParam(const string& arg, const char* op);
    string getParam(const string& arg, const char* op1, const char* op2);
    bool isOption(const string arg, const char* op);
    bool isOption(const string& arg, const char* op1, const char* op2);
    void isOptionError(const string& arg, const string& errorInfo);
    bool isParamOption(const string& arg, const char* option);
    bool isParamOption(const string& arg, const char* option1, const char* option2);
    void parseOption(const string& arg, const string& errorInfo);
};

#ifndef ASTYLE_LIB

//----------------------------------------------------------------------------
// ASConsole class for console build
//----------------------------------------------------------------------------

class ASConsole
{
private:                    // variables
    ASFormatter& formatter; // reference to the ASFormatter object
    ASLocalizer localizer;  // ASLocalizer object
    // command line options
    bool isRecursive;                // recursive option
    string origSuffix;               // suffix= option
    bool noBackup;                   // suffix=none option
    bool preserveDate;               // preserve-date option
    bool isVerbose;                  // verbose option
    bool isQuiet;                    // quiet option
    bool isFormattedOnly;            // formatted lines only option
    bool ignoreExcludeErrors;        // don't abort on unmatched excludes
    bool ignoreExcludeErrorsDisplay; // don't display unmatched excludes
    bool optionsFileRequired;        // options= option
    bool useAscii;                   // ascii option
    // other variables
    bool hasWildcard;           // file name includes a wildcard
    size_t mainDirectoryLength; // directory length to be excluded in displays
    bool filesAreIdentical;     // input and output files are identical
    bool lineEndsMixed;         // output has mixed line ends
    int linesOut;               // number of output lines
    int filesFormatted;         // number of files formatted
    int filesUnchanged;         // number of files unchanged
    char outputEOL[4];          // current line end
    char prevEOL[4];            // previous line end

    string optionsFileName; // file path and name of the options file to use
    string targetDirectory; // path to the directory being processed
    string targetFilename;  // file name being processed

    vector<string> excludeVector;     // exclude from wildcard hits
    vector<bool> excludeHitsVector;   // exclude flags for eror reporting
    vector<string> fileNameVector;    // file paths and names from the command line
    vector<string> optionsVector;     // options from the command line
    vector<string> fileOptionsVector; // options from the options file
    vector<string> fileName;          // files to be processed including path

public:
    ASConsole(ASFormatter& formatterArg)
        : formatter(formatterArg)
    {
        // command line options
        isRecursive = false;
        origSuffix = ".orig";
        noBackup = false;
        preserveDate = false;
        isVerbose = false;
        isQuiet = false;
        isFormattedOnly = false;
        ignoreExcludeErrors = false;
        ignoreExcludeErrorsDisplay = false;
        optionsFileRequired = false;
        useAscii = false;
        // other variables
        hasWildcard = false;
        filesAreIdentical = true;
        lineEndsMixed = false;
        outputEOL[0] = '\0';
        prevEOL[0] = '\0';
        mainDirectoryLength = 0;
        filesFormatted = 0;
        filesUnchanged = 0;
        linesOut = 0;
    }

    // functions
    void convertLineEnds(ostringstream& out, int lineEnd);
    FileEncoding detectEncoding(const char* data, size_t dataSize) const;
    void error() const;
    void error(const char* why, const char* what) const;
    void formatCinToCout();
    vector<string> getArgvOptions(int argc, char** argv) const;
    bool fileNameVectorIsEmpty();
    int getFilesFormatted();
    int getFilesUnchanged();
    bool getIgnoreExcludeErrors();
    bool getIgnoreExcludeErrorsDisplay();
    bool getIsFormattedOnly();
    bool getIsQuiet();
    bool getIsRecursive();
    bool getIsVerbose();
    bool getLineEndsMixed();
    bool getNoBackup();
    string getLanguageID() const;
    string getNumberFormat(int num, size_t = 0) const;
    string getNumberFormat(int num, const char* groupingArg, const char* separator) const;
    string getOptionsFileName();
    bool getOptionsFileRequired();
    string getOrigSuffix();
    bool getPreserveDate();
    void processFiles();
    void processOptions(vector<string>& argvOptions);
    void setIgnoreExcludeErrors(bool state);
    void setIgnoreExcludeErrorsAndDisplay(bool state);
    void setIsFormattedOnly(bool state);
    void setIsQuiet(bool state);
    void setIsRecursive(bool state);
    void setIsVerbose(bool state);
    void setNoBackup(bool state);
    void setOptionsFileName(string name);
    void setOptionsFileRequired(bool state);
    void setOrigSuffix(string suffix);
    void setPreserveDate(bool state);
    void setProgramLocale();
    void standardizePath(string& path, bool removeBeginningSeparator = false) const;
    bool stringEndsWith(const string& str, const string& suffix) const;
    void updateExcludeVector(string suffixParam);
    size_t Utf8Length(const char* data, size_t len, FileEncoding encoding) const;
    size_t Utf8ToUtf16(char* utf8In, size_t inLen, FileEncoding encoding, char* utf16Out) const;
    size_t Utf16Length(const char* data, size_t len) const;
    size_t Utf16ToUtf8(char* utf16In, size_t inLen, FileEncoding encoding, bool firstBlock, char* utf8Out) const;
    void verifyCinPeek() const;

    // for unit testing
    vector<string> getExcludeVector();
    vector<bool> getExcludeHitsVector();
    vector<string> getFileNameVector();
    vector<string> getOptionsVector();
    vector<string> getFileOptionsVector();
    vector<string> getFileName();

private:
    ASConsole& operator=(ASConsole&); // not to be implemented
    void correctMixedLineEnds(ostringstream& out);
    void formatFile(const string& fileName_);
    string getCurrentDirectory(const string& fileName_) const;
    void getFileNames(const string& directory, const string& wildcard);
    void getFilePaths(string& filePath);
    string getParam(const string& arg, const char* op);
    void initializeOutputEOL(LineEndFormat lineEndFormat);
    bool isOption(const string& arg, const char* op);
    bool isOption(const string& arg, const char* op1, const char* op2);
    bool isParamOption(const string& arg, const char* option);
    bool isPathExclued(const string& subPath);
    void printHelp() const;
    void printMsg(const char* msg, const string& data) const;
    void printSeparatingLine() const;
    void printVerboseHeader() const;
    void printVerboseStats(clock_t startTime) const;
    FileEncoding readFile(const string& fileName, stringstream& in) const;
    void removeFile(const char* fileName_, const char* errMsg) const;
    void renameFile(const char* oldFileName, const char* newFileName, const char* errMsg) const;
    void setOutputEOL(LineEndFormat lineEndFormat, const char* currentEOL);
    void sleep(int seconds) const;
    int swap8to16bit(int value) const;
    int swap16bit(int value) const;
    int waitForRemove(const char* oldFileName) const;
    int wildcmp(const char* wild, const char* data) const;
    void writeFile(const string& fileName_, FileEncoding encoding, ostringstream& out) const;
#ifdef _WIN32
    void displayLastError();
#endif
};
#endif // ASTYLE_LIB

} // end of namespace astyle

//----------------------------------------------------------------------------
// declarations for java native interface (JNI) build
// global because they are called externally and are NOT part of the namespace
//----------------------------------------------------------------------------

#ifdef ASTYLE_JNI
void STDCALL javaErrorHandler(int errorNumber, const char* errorMessage);
char* STDCALL javaMemoryAlloc(unsigned long memoryNeeded);
// the following function names are constructed from method names in the calling java program
extern "C" EXPORT jstring STDCALL Java_AStyleInterface_AStyleGetVersion(JNIEnv* env, jclass);
extern "C" EXPORT jstring STDCALL
    Java_AStyleInterface_AStyleMain(JNIEnv* env, jobject obj, jstring textInJava, jstring optionsJava);
#endif //  ASTYLE_JNI

#endif // closes ASTYLE_MAIN_H
