/* ajson.hh
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2017-2023 Ralf Hoffmann.
 * You can contact me at: ralf@boomerangsworld.de
 *   or http://www.boomerangsworld.de/worker
 *
 * 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.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef AJSON_H
#define AJSON_H

#include <iostream>
#include <memory>
#include <string>
#include <map>
#include <vector>
#include <list>

#include "ajson_scan.hh"

namespace AJSON {

    class JSONType {
    public:
        virtual ~JSONType() = 0;
	    virtual int dump( std::ostream &out, int indent_level ) = 0;
    };

    class JSONObject : public JSONType {
    public:
        int dump( std::ostream &out, int indent_level );
        std::shared_ptr< JSONType > get( const std::string &key );

        std::shared_ptr< JSONType > set( const std::string &key, std::shared_ptr< JSONType > value );

        std::list< std::string > keys() const;
    private:
        std::map< std::string, std::shared_ptr< JSONType > > m_elements;
    };

    class JSONArray : public JSONType {
    public:
        int dump( std::ostream &out, int indent_level );

        size_t size() const;
        std::shared_ptr< JSONType > get( size_t index );

        int append( std::shared_ptr< JSONType > value );
    private:
        std::vector< std::shared_ptr< JSONType > > m_elements;
    };

    class JSONString : public JSONType {
    public:
        JSONString( const std::string &value );

        int dump( std::ostream &out, int indent_level );

        std::string get_value() const;
    private:
        std::string m_value;
    };

    class JSONNumber : public JSONType {
    public:
        JSONNumber( const std::string &value );
        JSONNumber( long int value );

        int dump( std::ostream &out, int indent_level );

        long int get_value() const;
    private:
        long int m_value = 0;
    };

    class JSONBoolean : public JSONType {
    public:
        JSONBoolean( bool value );

        int dump( std::ostream &out, int indent_level );

        bool get_value() const;
    private:
        bool m_value = 0;
    };

    std::shared_ptr< JSONType > load( const std::string &filename );
    int dump( std::shared_ptr< JSONType > value, const std::string &filename );

	std::shared_ptr<JSONObject> make_object();
	std::shared_ptr<JSONArray> make_array();
	std::shared_ptr<JSONString> make_string( const std::string &value );
	std::shared_ptr<JSONNumber> make_number( long int value );
	std::shared_ptr<JSONNumber> make_number( const std::string &value );
	std::shared_ptr<JSONBoolean> make_boolean( bool value );

	std::shared_ptr<JSONString> as_string( std::shared_ptr< JSONType > );
	std::shared_ptr<JSONArray> as_array( std::shared_ptr< JSONType > );
	std::shared_ptr<JSONObject> as_object( std::shared_ptr< JSONType > );
	std::shared_ptr<JSONNumber> as_number( std::shared_ptr< JSONType > );
	std::shared_ptr<JSONBoolean> as_boolean( std::shared_ptr< JSONType > );

    class JSONParser {
    public:
        std::shared_ptr< JSONType > parse( const std::string &data );
    private:
        std::list< ajson_token_t > m_tokens;

        ajson_token_t get_current_token() const;
        void advance_token();

        bool has_next_token() const;

        std::shared_ptr< JSONType > value();
        std::shared_ptr< JSONType > object();
        std::shared_ptr< JSONType > array();
    };
};

#endif /* AJSON_H */
