//
//  BlueprintParserCore.h
//  snowcrash
//
//  Created by Zdenek Nemec on 5/4/13.
//  Copyright (c) 2013 Apiary Inc. All rights reserved.
//

#ifndef SNOWCRASH_BLUEPRINTPARSERCORE_H
#define SNOWCRASH_BLUEPRINTPARSERCORE_H

#include <algorithm>
#include <sstream>
#include "ParserCore.h"
#include "SourceAnnotation.h"
#include "MarkdownBlock.h"
#include "BlueprintSection.h"
#include "HTTP.h"
#include "Blueprint.h"
#include "BlueprintUtility.h"
#include "StringUtility.h"
#include "SymbolTable.h"

namespace snowcrash {
    
    /**
     *  \brief Blueprint Parser Options.
     *
     *  Controls blueprint parser behavior.
     */
    enum BlueprintParserOption {
        RenderDescriptionsOption = (1 << 0),    /// < Render Markdown in description.
        RequireBlueprintNameOption = (1 << 1)   /// < Treat missing blueprint name as error
    };
    
    typedef unsigned int BlueprintParserOptions;
    
    /**
     *  \brief Parsing subroutine result
     *
     *  Consists of a parsing result report (first) and
     *  %BlockIterator (second) pointing to the last parsed
     *  markdown block.
     */
    typedef std::pair<Result, BlockIterator> ParseSectionResult;
    
    
    /**
     *  Parser Core Data
     */
    struct BlueprintParserCore {
        BlueprintParserCore(BlueprintParserOptions opts,
                            const SourceData& src,
                            const Blueprint& bp)
        : options(opts), sourceData(src), blueprint(bp) {}
        
        /** Parser Options */
        BlueprintParserOptions options;
        
        /** Symbol Table */
        SymbolTable symbolTable;
        
        /** Source Data */
        const SourceData& sourceData;
        
        /** AST being parsed **/
        const Blueprint& blueprint;
        
    private:
        BlueprintParserCore();
        BlueprintParserCore(const BlueprintParserCore&);
        BlueprintParserCore& operator=(const BlueprintParserCore&);
    };
    
    /**
     *  SectionType Parser prototype.
     */
    template<class T>
    struct SectionParser {
        
        /**
         *  \brief  Parse section's blocks.
         *  \param  section     Actual section being parsed.
         *  \param  cur         Cursor within the section boundaries.
         *  \param  parser      Parser instance.
         *  \param  output      AST node parsed.
         *  \return %ParseSectionResult pointing to the last block parsed & including 
         *  any possible source annotations in the form of results or warnings.
         */
        static ParseSectionResult ParseSection(const BlueprintSection& section,
                                               const BlockIterator& cur,
                                               BlueprintParserCore& parser,
                                               T& output);
        
        /**
         *  \brief  Optional post-parse processing.
         */
        static void Finalize(const SectionBounds& bounds,
                             BlueprintParserCore& parser,
                             T& output,
                             Result& result);
    };
    
    /**
     *  \brief Internal list items classifier prototype.
     *
     *  The classifier might look ahead.
     *  DO NOT provide generic implementation.
     */
    template <class T>
    FORCEINLINE SectionType ClassifyInternaListBlock(const BlockIterator& begin,
                                                     const BlockIterator& end);
    /**
     *  \brief Classify a block with children list items.
     *
     *  Classifies internal list block & descend to children list block classifiers.
     *  DO NOT provide generic implementation.
     */
    template <class T>
    FORCEINLINE SectionType ClassifyChildrenListBlock(const BlockIterator& begin,
                                                      const BlockIterator& end);
        
    /**
     *  \brief Block Classifier prototype.
     *
     *  The classifier might look ahead.
     */
    template <class T>
    FORCEINLINE SectionType ClassifyBlock(const BlockIterator& begin,
                                          const BlockIterator& end,
                                          const SectionType& context);
    
    // Forward declaration of classifier helpers
    extern bool HasResourceGroupSignature(const MarkdownBlock& block);
    extern bool HasActionSignature(const MarkdownBlock& block);
    extern bool HasResourceSignature(const MarkdownBlock& block);
    extern bool HasPayloadSignature(const BlockIterator& begin, const BlockIterator& end);
    extern bool HasPayloadAssetSignature(const BlockIterator& begin, const BlockIterator& end);
    extern bool HasAssetSignature(const BlockIterator& begin, const BlockIterator& end);
    extern bool HasHeaderSignature(const BlockIterator& begin, const BlockIterator& end);
    extern bool HasParametersSignature(const BlockIterator& begin, const BlockIterator& end);
    
    /**
     *  \brief A Markdown block parser.
     *
     *  Iterates over blocks classifying sections and calling relevant %SectionParser P<T>.
     */
    template <class T, class P>
    struct BlockParser : public P {
        
        // Iterate blocks, classify & parse
        static ParseSectionResult Parse(const BlockIterator& begin,
                                        const BlockIterator& end,
                                        const BlueprintSection& parentSection,
                                        BlueprintParserCore& parser,
                                        T& output) {
            Result result;
            SectionType currentSectionType = UndefinedSectionType;
            BlockIterator currentBlock = begin;
            while (currentBlock != end) {
                
                currentSectionType = ClassifyBlock<T>(currentBlock, end, currentSectionType);
                BlueprintSection currentSection(currentSectionType, std::make_pair(begin, end), parentSection);
                
                ParseSectionResult sectionResult = P::ParseSection(currentSection,
                                                                   currentBlock,
                                                                   parser,
                                                                   output);
                
                result += sectionResult.first;
                if (result.error.code != Error::OK)
                    break;
                
                if (sectionResult.second == currentBlock)
                    break;

                currentBlock = sectionResult.second;

                if (currentSectionType == UndefinedSectionType)
                    break;
            }
            
            P::Finalize(std::make_pair(begin, currentBlock), parser, output, result);
            
            return std::make_pair(result, currentBlock);
        }        
    };
}

#endif