/*
 * File Name: document_impl.h
 */

/*
 * This file is part of uds-plugin-plaintext.
 *
 * uds-plugin-plaintext 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.
 *
 * uds-plugin-plaintext 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, see <http://www.gnu.org/licenses/>.
 */

/**
 * Copyright (C) 2008 iRex Technologies B.V.
 * All rights reserved.
 */

#ifndef TEXT_PLUGIN_DOCUMENT_IMPL_H_
#define TEXT_PLUGIN_DOCUMENT_IMPL_H_

#include <string>
#include <vector>
#include "plugin_inc.h"
#include "interfaces_utils.h"
#include "signal_slot.h"
#include "listeners.h"
#include "text_model.h"
#include "text_controller.h"
#include "string_impl.h"

using namespace utils;

namespace text
{

struct RangeImpl
{
public:
    RangeImpl(const Range& range)
    {
        start_anchor = new StringImpl(range.start.to_string());
        end_anchor = new StringImpl(range.end.to_string());
    }

    ~RangeImpl()
    {
        delete start_anchor;
        delete end_anchor;
    }

public:
    UDSString* start_anchor;
    UDSString* end_anchor;
};

class PluginViewImpl;

/// @brief Implement all necessary interfaces for document object.
/// If the interface is not supported, the impl can remove 
/// them from parent class list.
class PluginDocImpl : public IPluginUnknown 
                    , public IPluginDocument 
                    , public IPluginDocNavigator
                    , public IPluginDocAttributes
                    , public IPluginEventBroadcaster
                    , public IPluginDocHyperlink
                    , public IPluginDocDictionary
                    , public IPluginDocMarker
                    , public IPluginDocSearch
{
public:
    PluginDocImpl();
    ~PluginDocImpl();

public:
    TextModel & get_model() { return document; }

public:
    /// The release signal.
    Signal<PluginDocImpl *> release_signal;

    /// Handle search done event.
    void on_search_done(const std::vector<Range>& result, const SearchContext* sc);

private:
    // IPluginUnknown.
    static PluginStatus query_interface_impl(
        IPluginUnknown      *thiz,
        const UDSString     *id, 
        void                **ptr );

    static int release_impl(
        IPluginUnknown      *thiz );

    // IPluginDocument.
    static PluginStatus open_impl(
        IPluginUnknown      *thiz, 
        const UDSString     *path);

    static PluginBool is_open_impl(
        IPluginUnknown      *thiz);

    static PluginStatus close_impl(
        IPluginUnknown      *thiz);

    static IPluginUnknown * create_view_impl(
        IPluginUnknown      *thiz);

    // IPluginDocNavigator
    static PluginStatus get_initial_anchor_impl(
        IPluginUnknown      *thiz, 
        UDSString           *anchor);

    static PluginStatus get_object_from_anchor_impl(
        IPluginUnknown      *thiz,
        const UDSString     *anchor, 
        PluginRange         *range);

    static PluginDocObjectType get_type_of_object_impl(
        IPluginUnknown      *thiz,
        const PluginRange   *range);
    
    static PluginStatus get_words_from_range_impl(
        IPluginUnknown      *thiz, 
        const PluginRange   *char_range, 
        PluginRange         *word_range );

    static PluginStatus get_text_from_range_impl(
        IPluginUnknown      *thiz, 
        const PluginRange   *range, 
        UDSString           *result );

    static PluginBool is_anchor_in_current_document_impl(
        IPluginUnknown      *thiz,
        const UDSString     *anchor );

    static PluginStatus get_file_name_from_anchor_impl(
        IPluginUnknown    *thiz,
        const UDSString   *anchor,
        UDSString         *file_name );

    static PluginStatus get_file_position_from_anchor_impl(
        IPluginUnknown    *thiz,
        const UDSString   *anchor,
        signed long long  *position );

    static int compare_anchor_location_impl(
        IPluginUnknown      *thiz,
        const UDSString     *anchor_a,
        const UDSString     *anchor_b );

    // IPluginDocAttributes.
    static PluginStatus get_attribute_impl(
        IPluginUnknown      *thiz,
        const UDSString     *key, 
        UDSString           *value );

    static PluginStatus set_attribute_impl(
        IPluginUnknown      *thiz,
        const UDSString     *key,
        const UDSString     *value );

    // IPluginEventBroadcaster
    static PluginStatus add_event_receiver_impl(
        IPluginUnknown      *thiz,
        const PluginEvent   plugin_event,
        EventFunc           callback,
        void                *user_data,
        unsigned long       *handler_id);

    static PluginStatus remove_event_receiver_impl(
        IPluginUnknown      *thiz,
        unsigned long       handler_id );

    // IPluginDocHyperlink
    static PluginBool is_hyperlink_impl(
        IPluginUnknown      *thiz,
        const PluginRange   *range );

    static PluginStatus get_target_from_hyperlink_impl(
        IPluginUnknown      *thiz,
        const PluginRange   *range, 
        UDSString           *anchor );

    // IPluginDocDictionary
    static PluginBool is_dictionary_impl( 
        IPluginUnknown      *thiz );

    // IPluginDocMarker. No such interface.
    // Place holder for these two functions.
    static IPluginUnknown* get_supported_marker_types_impl(
        IPluginUnknown  *thiz );

    static PluginStatus request_marker_trees_impl(
        IPluginUnknown     *thiz, 
        const unsigned int uds_private_size );

    // IPluginDocSearch
    static IPluginUnknown * create_search_criteria_impl(
        IPluginUnknown      *thiz );

    static PluginStatus request_search_next_impl(
        IPluginUnknown      *thiz,
        IPluginUnknown      *criteria,
        const UDSString     *from_anchor,
        const unsigned int  search_id);

    static PluginStatus request_search_all_impl( 
        IPluginUnknown *thiz,
        IPluginUnknown *criteria,
        const unsigned int  search_id);

    static PluginStatus abort_search_impl(
        IPluginUnknown     *thiz,
        const unsigned int search_id);

private:
    typedef PluginViewImpl * ViewPtr;
    
private:
    static utils::ObjectTable<PluginDocImpl> g_instances_table;

private:
    TextController *controller; ///< Controller instance.
    utils::Listeners listeners; ///< All listeners.
    text::TextModel document;   ///< The document model.

private:
    void init_doc_attributes();
    typedef std::map<std::string, std::string> DocAttrMap;
    typedef DocAttrMap::iterator               DocAttrMapIter;
    DocAttrMap doc_attr_map;
};

};  // namespace text

#endif

