/*
 * File Name: text_controller.cpp
 */

/*
 * 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.
 */

#include "log.h"
#include "text_tasks.h"
#include "text_view.h"
#include "text_controller.h"

namespace text
{

TextController::TextController(TextModel *_model, TextView *_view)
: model(_model)
, view(_view)
, pagination_paused(false)
{
    // Set controller for view.
    view->set_controller(this);
}

TextController::~TextController()
{
}

void TextController::start()
{
    // Launch worker thread.
    thread.start();
}

void TextController::stop()
{
    // Stop worker thread, wait until all tasks done.
    thread.stop();
}

void TextController::render(unsigned int id, unsigned int page_index, void *data, unsigned char* bmp)
{
    Position start_pos;
    if (view->get_anchor_by_page(page_index, start_pos))
    {
        render(id, start_pos, data, bmp);
    }
    else
    {
        ERRORPRINTF("Can't render page %d because it does not exist.\n", page_index);
    }
}

void TextController::render(unsigned int id, const Position& start_pos, void *data, unsigned char* bmp)
{
    LOGPRINTF("About to launch render task.");
    view->check_page_table(start_pos);
    thread.prepend_task(new RenderTask(id, view, start_pos, data, bmp), true);
}

void TextController::paginate(const Position& start, bool send_start_notification)
{
    pagination_pending = true;
    PaginationTask *task = new PaginationTask(view, start, !send_start_notification);
    task->abort_signal.add_slot(this, &TextController::on_pagination_aborted);
    view->pagination_end_signal.add_slot(this, &TextController::on_pagination_finished);
    thread.append_task(task);
}

void TextController::on_pagination_finished(unsigned int, unsigned int)
{
    if (!pagination_paused)
    {
        pagination_pending = false;
    }
}

void TextController::on_pagination_aborted(const Position& start)
{
    // If repagination is needed, we don't need to launch a same
    // pagination again. A new pagination task will be launched
    // by render task soon.
    //
    // Also when pagination is paused, we don't want to restart
    // the pagination immediately
    //
    if ((!pagination_paused) && (!view->need_repagination()))
    {
        paginate(start, false /* don't send pagination start notification */);
    }
}

void TextController::pause_pagination()
{
    TRACEFUNCTION();

    if (pagination_pending)
    {
        pagination_paused = true;
        
        unsigned int total_pages = view->get_page_count();
        unsigned int current_page = view->get_current_page_index();
        
        // Reporting pagination done to UDS through our internal pagination end signal
        // UDS probably doesn't receive this event because the document window is
        // about to be deactivated (hence, UDS will unsubscribe from plugin events),
        // however I still think it is good practice to try to notify UDS anyway.
        // [MdB]
        view->pagination_end_signal.broadcast(current_page, total_pages);  
    
        PaginationAbortTask *task = new PaginationAbortTask(view);
        thread.prepend_task(task, true /* Cancel running task */);
    }
}

void TextController::restart_pagination()
{
     TRACEFUNCTION();

   
    // Only restart pagination if there is a need
    if (pagination_pending)
    {
        pagination_paused = false;

        Position start_pos;
        view->check_page_table(start_pos);
        paginate(start_pos, false /* don't send pagination start notification */);
    }
}


void TextController::search(SearchContext* search_context)
{
    SearchTask* task = new SearchTask(model, search_context);
    task->abort_signal.add_slot(this, &TextController::on_search_aborted);
    thread.prepend_task(task, true);
}

void TextController::on_search_aborted(SearchContext* sc)
{
    SearchTask* task = new SearchTask(model, sc);
    task->abort_signal.add_slot(this, &TextController::on_search_aborted);
    thread.prepend_task(task, false);
}

}

