/***********************************************************************************

	Copyright (C) 2007-2018 Ahmet Öztürk (aoz_2@yahoo.com)

    This file is part of Lifeograph.

    Lifeograph 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 3 of the License, or
    (at your option) any later version.

    Lifeograph 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 Lifeograph.  If not, see <http://www.gnu.org/licenses/>.

***********************************************************************************/

#include <thread>
#include <chrono>

#include <gtkmm/table.h>
#include <gtkmm/label.h>

#include "lifeograph.hpp"
#include "app_window.hpp"
#include "helpers.hpp"
#include "diary.hpp"	// for LIFEO::PASSPHRASE_MIN_SIZE
#include "dialog_password.hpp"


using namespace LIFEO;


// PASSWORD DIALOG =================================================================================
DialogPassword* DialogPassword::ptr = nullptr;

DialogPassword::DialogPassword( BaseObjectType* cobject,
                                const Glib::RefPtr< Gtk::Builder >& refbuilder )
:   DialogEvent( cobject, refbuilder ), m_ptr2diary( nullptr )
{
    auto builder{ Lifeograph::get_builder() };
    builder->get_widget( "B_password_go", m_button_go );
    builder->get_widget_derived( "E_password_current", m_entry_current );
    builder->get_widget_derived( "E_password_new", m_entry_new );
    builder->get_widget_derived( "E_password_confirm", m_entry_confirm );
    builder->get_widget( "L_password_msg", m_label_msg );
    builder->get_widget( "L_password_path", m_label_path );
    builder->get_widget( "G_password_new", m_grid_new );
    builder->get_widget( "G_password_authenticate", m_grid_authenticate );
    builder->get_widget( "B_password_authenticate", m_button_authenticate );
    builder->get_widget( "I_password_new", m_image_new );
    builder->get_widget( "I_password_confirm", m_image_confirm );

    set_response_sensitive( RESPONSE_GO, false );
    set_transient_for( *AppWindow::p );

    // SIGNALS
    m_entry_current->signal_changed().connect(
            sigc::mem_fun( this, &DialogPassword::handle_entry_changed ) );

    m_button_authenticate->signal_clicked().connect(
            sigc::mem_fun( this, &DialogPassword::authenticate ) );

    m_entry_new->signal_changed().connect(
            sigc::mem_fun( this, &DialogPassword::check_match ) );
    m_entry_confirm->signal_changed().connect(
            sigc::mem_fun( this, &DialogPassword::check_match ) );
}

int
DialogPassword::launch( OperationType ot, Diary* diary, bool flag_again )
{
    if( ptr == nullptr )
        Lifeograph::get_builder()->get_widget_derived( "D_password", ptr );

    ptr->m_ptr2diary = diary;
    ptr->m_ot = ot;

    ptr->m_label_path->set_text( diary->get_name() );

    ptr->m_entry_current->set_visible( ot & OT_CURRENT );
    ptr->m_entry_current->set_sensitive( ot & OT_CURRENT );
    ptr->m_grid_new->set_visible( ot & OT_NEW );
    ptr->m_grid_authenticate->set_visible( ot == OT_CHANGE );
    ptr->m_entry_new->set_sensitive( ot & OT_NEW );
    ptr->m_entry_confirm->set_sensitive( ot & OT_NEW );
    ptr->m_image_new->set_sensitive( ot != OT_CHANGE );
    ptr->m_image_confirm->set_sensitive( ot != OT_CHANGE );

    if( ot != OT_ADD )
        ptr->m_entry_current->grab_focus();

    switch( ot )
    {
        case OT_AUTHENTICATE:
        case OT_OPEN:
            ptr->m_button_go->set_label( _( "Continue" ) );
            break;
        case OT_ADD:
            ptr->m_button_go->set_label( _( "Add Password" ) );
            ptr->m_entry_new->grab_focus();
            break;
        case OT_CHANGE:
            ptr->m_button_go->set_label( _( "Change Password" ) );
            break;
        default:
            break;
    }

    if( flag_again )
    {
        const std::chrono::seconds sleep_duration( SLEEP_DURATION );
        std::this_thread::sleep_for( sleep_duration );
        ptr->m_label_msg->set_text( _( "Wrong password. Please retry..." ) );
    }
    else
    {
        switch( ot )
        {
            case OT_AUTHENTICATE:
            case OT_OPEN:
                ptr->m_label_msg->set_text( _( "Please enter password for" ) );
                break;
            case OT_ADD:
                ptr->m_label_msg->set_text( _( "Please enter a new password for" ) );
                break;
            case OT_CHANGE:
                ptr->m_label_msg->set_text(
                        _( "Please enter the current and new passwords for" ) );
                break;
            default:
                break;
        }
    }

    int ret_value( ptr->run() );

    if( ret_value == RESPONSE_GO )
    {
        if( ot == OT_AUTHENTICATE )
        {
            if( ! diary->compare_passphrase( ptr->m_entry_current->get_text() ) )
            {
                ptr->m_entry_current->set_text( "" );
                return launch( ot, diary, true );
            }
        }
        else
        {
            diary->set_passphrase( ( ot & OT_NEW ) ?
                    ptr->m_entry_new->get_text() : ptr->m_entry_current->get_text() );
        }
    }

    ptr->m_entry_current->set_text( "" );
    ptr->m_entry_new->set_text( "" );
    ptr->m_entry_confirm->set_text( "" );
    ptr->hide();

    return ret_value;
}

void
DialogPassword::handle_entry_changed()
{
    bool size_ok( m_entry_current->get_text().size() >= PASSPHRASE_MIN_SIZE );

    if( m_ot == OT_CHANGE )
        m_button_authenticate->set_sensitive( size_ok );
    else
        set_response_sensitive( RESPONSE_GO, size_ok );
}

void
DialogPassword::authenticate()
{
    if ( m_ptr2diary->compare_passphrase( m_entry_current->get_text() ) )
    {
        m_entry_new->set_sensitive( true );
        m_entry_confirm->set_sensitive( true );
        m_image_new->set_sensitive( true );
        m_image_confirm->set_sensitive( true );
        m_entry_new->grab_focus();
        m_entry_current->set_sensitive( false );
        m_button_authenticate->set_sensitive( false );
    }
    else
    {
        const std::chrono::seconds sleep_duration( SLEEP_DURATION );
        std::this_thread::sleep_for( sleep_duration );
        m_entry_current->set_text( "" );
    }
}

void
DialogPassword::check_match()
{
    Glib::ustring passphrase( m_entry_new->get_text() );

    if( passphrase.size() >= LIFEO::PASSPHRASE_MIN_SIZE )
    {
        m_image_new->set_from_icon_name( "gtk-yes", Gtk::ICON_SIZE_MENU );
        if( passphrase == m_entry_confirm->get_text() )
        {
            m_image_confirm->set_from_icon_name( "gtk-yes", Gtk::ICON_SIZE_MENU );
            set_response_sensitive( RESPONSE_GO, true );
        }
        else
        {
            m_image_confirm->set_from_icon_name( "gtk-no", Gtk::ICON_SIZE_MENU );
            set_response_sensitive( RESPONSE_GO, false );
        }
    }
    else
    {
        m_image_new->set_from_icon_name( "gtk-no", Gtk::ICON_SIZE_MENU );
        m_image_confirm->set_from_icon_name( "gtk-no", Gtk::ICON_SIZE_MENU );
        set_response_sensitive( RESPONSE_GO, false );
    }
}
