#ifndef PASTELSYS_ENSURE_HPP
#define PASTELSYS_ENSURE_HPP
#include "pastel/sys/ensure.h"
#include <iostream>
#ifdef _MSC_VER
#include <crtdbg.h>
#endif
namespace Pastel
{
    namespace Ensure_
    {
        inline void invariantFailure()
        {
            std::cout << std::flush;
            #ifdef _MSC_VER
                // If on Visual Studio, create a breakpoint
                // here, and get back to the debugger.
                _CrtDbgBreak();
            #endif
            throw InvariantFailure();
        }
        inline void reportParameters()
        {
        }
        template <
            typename Type,
            typename... TypeSet>
        void reportParameters(
            ParameterInfo<Type> parameter, 
            ParameterInfo<TypeSet>... parameterSet)
        {
            if (parameter.name)
            {
                std::cout << parameter.name << " == "
                    << parameter.value << std::endl;
            }
            reportParameters(parameterSet...);
        }
        template <typename... TypeSet>
        void report(
            const char* testText,
            const char* functionName,
            const char* fileName, 
            int lineNumber,
            ParameterInfo<TypeSet>... parameterSet)
        {
            std::cout << "File: ";
            if (fileName)
            {
                std::cout << fileName;
            }
            else
            {
                std::cout << "Not available";
            }
            std::cout << std::endl;
            std::cout << "Line: ";
            if (lineNumber >= 0)
            {
                std::cout << lineNumber;
            }
            else
            {
                std::cout << "Not available";
            }
            std::cout << std::endl;
            std::cout << "Function: ";
            if (functionName)
            {
                std::cout << functionName;
            }
            else
            {
                std::cout << "Not available";
            }
            std::cout << std::endl;
            std::cout << "Expression: ";
            if (testText)
            {
                std::cout << testText;
            }
            else
            {
                std::cout << "Not available";
            }
            std::cout << std::endl;
            if (sizeof...(TypeSet) > 0)
            {
                std::cout << "where" << std::endl;
                reportParameters(parameterSet...);
            }
            std::cout << std::endl << std::endl;
        }
        template <typename... TypeSet>
        void error(
            const char* testText,
            const char* functionName,
            const char* fileName, 
            int lineNumber,
            ParameterInfo<TypeSet>... parameterSet)
        {
            std::cout << std::endl;
            std::cout << "Precondition check failed."
                << std::endl;
            report(testText,
                functionName,
                fileName, 
                lineNumber,
                parameterSet...);
            invariantFailure();
        }
        template <typename... TypeSet>
        void assertionError(
            const char* testText,
            const char* functionName,
            const char* fileName, 
            int lineNumber,
            ParameterInfo<TypeSet>... parameterSet)
        {
            std::cout << std::endl;
            std::cout << "Internal check failed." 
                << std::endl;
            report(testText,
                functionName,
                fileName, 
                lineNumber,
                parameterSet...);
            invariantFailure();
        }
    }
}
#endif