// ライセンス: 最新のGPL

//#define _DEBUG
#include "jddebug.h"

#include "messageadmin.h"
#include "messageviewbase.h"
#include "post.h"

#include "jdlib/miscutil.h"
#include "jdlib/misctime.h"

#include "dbtree/interface.h"

#include "httpcode.h"
#include "command.h"
#include "viewfactory.h"
#include "controlutil.h"
#include "controlid.h"

#include <sstream>
#include <sys/time.h>


using namespace MESSAGE;


MessageViewBase::MessageViewBase( const std::string& url )
    : SKELETON::View( url ),
      m_post( 0 ),
      m_preview( 0 ),
      m_button_write( Gtk::Stock::NEW ),
      m_button_cancel( Gtk::Stock::CLOSE )
{
#ifdef _DEBUG
    std::cout << "MessageViewBase::MessageViewBase " << get_url() << std::endl;
#endif

    // コントロールモード設定
    get_control().set_mode( CONTROL::MODE_MESSAGE );
}



MessageViewBase::~MessageViewBase()
{
#ifdef _DEBUG
    std::cout << "MessageViewBase::~MessageViewBase " << get_url() << std::endl;
#endif

    if( m_preview ) delete m_preview;
    m_preview = NULL;

    if( m_post ) delete m_post;
    m_post = NULL;
}



//
// セットアップ
//
void MessageViewBase::setup_view()
{
    pack_widget();
}


//
// コマンド
//
bool MessageViewBase::set_command( const std::string& command, const std::string& arg )
{
    if( command == "empty" ) return get_message().empty();

    if( command == "loading" ){
        if( !m_post ) return false;
        return m_post->is_loading();
    }

    return false;
}



//
// 名前やメールを保存
//
void MessageViewBase::save_name()
{
    bool check_fixname = m_check_fixname.get_active();
    bool check_fixmail = m_check_fixmail.get_active();

    if( check_fixname != DBTREE::write_fixname( get_url() ) ) DBTREE::set_write_fixname( get_url(), check_fixname );
    if( check_fixname ){
        std::string name = m_entry_name.get_text();
        if( name != DBTREE::write_name( get_url() ) ) DBTREE::set_write_name( get_url(), name );
    }

    if( check_fixmail != DBTREE::write_fixmail( get_url() ) ) DBTREE::set_write_fixmail( get_url(), check_fixmail );
    if( check_fixmail ){
        std::string mail = m_entry_mail.get_text();
        if( mail != DBTREE::write_mail( get_url() ) ) DBTREE::set_write_mail( get_url(), mail );
    }
}



//
// ツールバーなどのパック
//
void MessageViewBase::pack_widget()
{
    // Gtk::Label を使うと勝手にリサイズするときがあるので
    // Gtk::Entry を使う。背景色を変えるときは on_realize() で指定する。
    m_entry_subject.set_editable( false );
    m_entry_subject.set_activates_default( false );
    m_entry_subject.set_has_frame( false );
    m_entry_subject.set_text( DBTREE::article_subject( get_url() ) );

    m_label_board.set_text( "[ " + DBTREE::board_name( get_url() ) + " ]  " );

    m_button_write.signal_clicked().connect( sigc::mem_fun( *this, &MessageViewBase::slot_write_clicked ) );
    m_button_cancel.signal_clicked().connect( sigc::mem_fun( *this, &MessageViewBase::slot_cancel_clicked ) );
    
    m_tooltip.set_tip( m_button_write, CONTROL::get_label_motion( CONTROL::ExecWrite ) );
    m_tooltip.set_tip( m_button_cancel, CONTROL::get_label_motion( CONTROL::CancelWrite ) );

    m_toolbar.pack_start( m_label_board, Gtk::PACK_SHRINK );
    m_toolbar.pack_start( m_entry_subject, Gtk::PACK_EXPAND_WIDGET, 2 );
    m_toolbar.pack_end( m_button_cancel, Gtk::PACK_SHRINK );
    m_toolbar.pack_end( m_button_write, Gtk::PACK_SHRINK );

    // 書き込みビュー
    m_label_name.set_alignment( Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER );
    m_label_mail.set_alignment( Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER );
    m_label_name.set_text( " 名前 " );
    m_label_mail.set_text( " メール " );

    m_check_fixname.set_label( "保存" );
    m_check_fixmail.set_label( "保存" );

    if( DBTREE::write_fixname( get_url() ) ){
        m_check_fixname.set_active();
        m_entry_name.set_text( DBTREE::write_name( get_url() ) );
    }
    if( DBTREE::write_fixmail( get_url() ) ){
        m_check_fixmail.set_active();
        m_entry_mail.set_text( DBTREE::write_mail( get_url() ) );
    }
    else m_entry_mail.set_text( "sage" );

    m_hbox_name_mail.pack_start( m_label_name, Gtk::PACK_SHRINK );
    m_hbox_name_mail.pack_start( m_check_fixname, Gtk::PACK_SHRINK );
    m_hbox_name_mail.pack_start( m_entry_name );
    m_hbox_name_mail.pack_start( m_label_mail, Gtk::PACK_SHRINK );
    m_hbox_name_mail.pack_start( m_check_fixmail, Gtk::PACK_SHRINK );
    m_hbox_name_mail.pack_start( m_entry_mail );

    m_msgview.pack_start( m_hbox_name_mail, Gtk::PACK_SHRINK );    
    m_msgview.pack_start( m_text_message );

    m_text_message.sig_key_release().connect( sigc::mem_fun(*this, &MessageViewBase::slot_key_release ) );    

    // プレビュー
    m_preview = CORE::ViewFactory( CORE::VIEW_ARTICLEPREVIEW, get_url() );

    m_notebook.append_page( m_msgview, "メッセージ" );
    m_notebook.append_page( *m_preview, "プレビュー" );
    m_notebook.signal_switch_page().connect( sigc::mem_fun( *this, &MessageViewBase::slot_switch_page ) );

    pack_start( m_toolbar, Gtk::PACK_SHRINK );
    pack_start( m_notebook );
}



void MessageViewBase::focus_view()
{
    m_text_message.focus_view();
}



//
// viewの操作
//
void MessageViewBase::operate_view( const int& control )
{
    if( control == CONTROL::None ) return;

    switch( control ){
            
            // 書き込まずに閉じる
        case CONTROL::CancelWrite:
            slot_cancel_clicked();
            break;

            // 書き込み実行
        case CONTROL::ExecWrite:
            slot_write_clicked();
            break;

        case CONTROL::TabLeft:
            tab_left();
            break;

        case CONTROL::TabRight:
            tab_right();
            break;
    }
}



//
// 書き込むボタン押した
//
void MessageViewBase::slot_write_clicked()
{
/* 書き込み確認(やってみたらうざかったので様子見)

    Gtk::Menu* popupmenu = dynamic_cast< Gtk::Menu* >( m_ui_manager->get_widget( "/popup_menu_write" ) );
    if( popupmenu ) popupmenu->popup( 0, gtk_get_current_event_time() );      
*/

    if( m_post && m_post->is_loading() ){
        Gtk::MessageDialog mdiag( "書き込み中です" );
        mdiag.run();
        return;
    }

    // fusianasan チェック
    if( DBTREE::default_noname( get_url() ) == "fusianasan" ) DBTREE::board_set_check_noname( get_url(), true );

    // 名無し書き込みチェック
    if( DBTREE::board_check_noname( get_url() ) ){

        std::string name = get_entry_name().get_text();
        if( name.empty() ){
            Gtk::MessageDialog mdiag( "名前欄が空白です。fusianasan 書き込みになる可能性があります。" );
            mdiag.run();
            return;
        }
    }

    write();
}


//
// キャンセルボタンを押した
//
void MessageViewBase::slot_cancel_clicked()
{
    close_view();
}


//
// テキストビューのキー操作
//
bool MessageViewBase::slot_key_release( GdkEventKey* event )
{
#ifdef _DEBUG
    guint key = event->keyval;
    bool ctrl = ( event->state ) & GDK_CONTROL_MASK;
    bool shift = ( event->state ) & GDK_SHIFT_MASK;
    bool alt = ( event->state ) & GDK_MOD1_MASK;

    std::cout << "MessageViewBase::slot_key_release"
              << " key = " << key
              << " ctrl = " << ctrl
              << " shift = " << shift
              << " alt = " << alt << std::endl;
#endif

    operate_view( SKELETON::View::get_control().key_press( event ) );

    return true;
}



//
// 閉じる
//
void MessageViewBase::close_view()
{
#ifdef _DEBUG
    std::cout << "MessageViewBase::close_view\n";
#endif

    MESSAGE::get_admin()->set_command( "close_currentview" );
}



//
// タブ左移動
//
void MessageViewBase::tab_left()
{
    int page = m_notebook.get_current_page();
    if( page != 1 ) return;

    m_notebook.set_current_page( 0 );
    focus_view();
}


//
// タブ右移動
//
void MessageViewBase::tab_right()
{
    int page = m_notebook.get_current_page();
    if( page != 0 ) return;

    m_notebook.set_current_page( 1 );
    m_preview->focus_view();
}



//
// 書き込み
//
void MessageViewBase::post_msg( const std::string& msg, bool new_article )
{
    if( m_post ) delete m_post;
    m_post = new Post( this, get_url(),  msg, new_article );
    m_post->sig_fin().connect( sigc::mem_fun( *this, &MessageViewBase::post_fin ) );
    m_post->post_msg();
}



//
// 書き込みが終わったら呼ばれる
//
void MessageViewBase::post_fin()
{
    int code = m_post->get_code();
    std::string location = m_post->location();

#ifdef _DEBUG
    std::cout << "MessageViewBase::post_fin" << std::endl
              << "code = " << code << std::endl
              << "location = " << location << std::endl;
#endif

    // 成功
    if( code == HTTP_OK
        || ( code == HTTP_REDIRECT && ! location.empty() ) // (まちBBSなどで)リダイレクトした場合
        ){
        m_text_message.set_text( std::string() );
        close_view();
        reload();
    }

    // タイムアウト
    else if( code == HTTP_TIMEOUT ){

        Gtk::MessageDialog mdiag( "タイムアウトしました\n\n書き込み自体は成功している可能性があります。\nメッセージのバックアップをとってからスレを再読み込みして下さい。" );
        mdiag.run();
    }

    // 失敗
    else if( code != HTTP_CANCEL ){

        Gtk::MessageDialog mdiag( "書き込みに失敗しました\n\n" + m_post->errmsg(), false, Gtk::MESSAGE_ERROR  );
        mdiag.run();
    }
}


//
// タブのページが切り替わったら呼ばれるslot
//
void MessageViewBase::slot_switch_page( GtkNotebookPage*, guint page )
{
#ifdef _DEBUG
    std::cout << "MessageViewBase::slot_switch_page : " << get_url() << " page = " << page << std::endl;
#endif

    // プレビュー表示
    if( m_preview && page == 1 ){

        std::string msg = m_text_message.get_text();
        msg = MISC::replace_str( msg, "<", "&lt;" );
        msg = MISC::replace_str( msg, ">", "&gt;" );
        msg = MISC::replace_str( msg, "\n", " <br> " );
        
        std::stringstream ss;

        if( ! m_entry_name.get_text().empty() ) ss << m_entry_name.get_text();
        else ss << DBTREE::default_noname( get_url() );

        ss << "<>" << m_entry_mail.get_text() << "<>";

        struct timeval tv;
        struct timezone tz;
        gettimeofday( &tv, &tz );
        ss << MISC::timettostr( tv.tv_sec );

        ss << " ID:???" << "<>" << msg << "<>\n";

#ifdef _DEBUG
        std::cout << ss.str() << std::endl;
#endif

        m_preview->set_command( "append_dat", ss.str() );
    }
    else MESSAGE::get_admin()->set_command( "focus_view" );
}
