/*
 * Copyright (c) 2013 Mark Liversedge (liversedge@gmail.com)
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "TabView.h"
#include "Tab.h"
#include "Context.h"
#include "Athlete.h"
#include "RideItem.h"
#include "BlankState.h"
#include "HomeWindow.h"
#include "GcWindowRegistry.h"
#include "TrainDB.h"
#include "RideNavigator.h"
#include "MainWindow.h"

#include "Settings.h"

TabView::TabView(Context *context, int type) : 
    QWidget(context->tab), context(context), type(type),
    _sidebar(true), _tiled(false), _selected(false), lastHeight(130), sidewidth(0), active(false),
    stack(NULL), splitter(NULL), mainSplitter(NULL), 
    sidebar_(NULL), bottom_(NULL), page_(NULL), blank_(NULL)
{
    // setup the basic widget
    QVBoxLayout *layout = new QVBoxLayout(this);
    setContentsMargins(0,0,0,0);
    layout->setContentsMargins(0,0,0,0);
    layout->setSpacing(0);

    stack = new QStackedWidget(this);
    stack->setContentsMargins(0,0,0,0);
    stack->setFrameStyle(QFrame::Plain | QFrame::NoFrame);
    stack->setMinimumWidth(500);
    stack->setMinimumHeight(500);

    layout->addWidget(stack);

    // the splitter
    splitter = new QSplitter(this);
    splitter->setHandleWidth(1);
    splitter->setStyleSheet(" QSplitter::handle { background-color: rgb(120,120,120); color: darkGray; }");
    splitter->setFrameStyle(QFrame::NoFrame);
    splitter->setContentsMargins(0, 0, 0, 0); // attempting to follow some UI guides
    splitter->setOpaqueResize(true); // redraw when released, snappier UI
    stack->insertWidget(0, splitter); // splitter always at index 0

    QString heading = tr("Compare Activities and Intervals");
    if (type == VIEW_HOME) heading = tr("Compare Date Ranges");

    mainSplitter = new ViewSplitter(Qt::Vertical, heading, this);
    mainSplitter->setHandleWidth(23);
    mainSplitter->setFrameStyle(QFrame::NoFrame);
    mainSplitter->setContentsMargins(0, 0, 0, 0); // attempting to follow some UI guides
    mainSplitter->setOpaqueResize(true); // redraw when released, snappier UI

    // the animator
    anim = new QPropertyAnimation(mainSplitter, "hpos");

    connect(splitter,SIGNAL(splitterMoved(int,int)), this, SLOT(splitterMoved(int,int)));
    connect(context,SIGNAL(configChanged(qint32)), this, SLOT(configChanged(qint32)));
}

TabView::~TabView()
{
    if (page_) page_->saveState();
}

void
TabView::setRide(RideItem*ride)
{
    page()->setProperty("ride", QVariant::fromValue<RideItem*>(dynamic_cast<RideItem*>(ride)));
}

void
TabView::splitterMoved(int pos,int)
{
    if (sidebar_ == NULL) return; // we haven't set sidebar yet.

    // show / hide sidebar as dragged..
    if ((pos == 0  && sidebarEnabled())) setSidebarEnabled(false);

    // remember the size the user selected
    sidewidth = splitter->sizes()[0];

    // we now have splitter settings for each view
    QString setting = QString("%1/%2").arg(GC_SETTINGS_SPLITTER_SIZES).arg(type);
    appsettings->setCValue(context->athlete->cyclist, setting, splitter->saveState());

    // if user moved us then tell ride navigator if
    // we are the analysis view
    // all a bit of a hack to stop the column widths from
    // being adjusted as the splitter gets resized and reset
    if (type == VIEW_ANALYSIS && active == false && context->tab->rideNavigator()->geometry().width() != 100)
        context->tab->rideNavigator()->setWidth(context->tab->rideNavigator()->geometry().width());
}

void
TabView::resizeEvent(QResizeEvent *)
{
    active = true; // we're mucking about, so ignore in splitterMoved ...

    if (sidewidth < 200) {
        sidewidth = splitter->sizes()[0];
    } else {

        // splitter sizes will have changed, so lets get the new
        // total width and set the handle back to where it was
        QList<int> csizes = splitter->sizes();
        if (csizes.count() == 2) {

            // total will have changed
            int tot = csizes[0] + csizes[1];
            if (tot >= sidewidth) {

                // set left back to where it was before!
                csizes[0] = sidewidth;
                csizes[1] = tot-sidewidth;
                splitter->setSizes(csizes);
                sidewidth = splitter->sizes()[0];
            }
        }
    }

    active = false;
}

void
TabView::setSidebar(QWidget *sidebar)
{
    sidebar_ = sidebar;
    splitter->insertWidget(0, sidebar);

    configChanged(CONFIG_APPEARANCE);
}

QString
TabView::ourStyleSheet()
{
    return QString::fromUtf8("QScrollBar { background-color: %1; border: 0px; }"
#ifndef Q_OS_MAC
           "QTabWidget { background: %1; }"
           "QTabWidget::pane { border: 1px solid %2; } "
           "QTextEdit { background: %1; }"
           "QTextEdit#metadata { background: %3; }"
#endif
           "QTreeView { background: %1; }"
           "QScrollBar:vertical {"
           "    border: 0px solid darkGray; "
           "    background:%1;"
           "    width: 8px;    "
           "    margin: 1px 1px 1px 1px;"
           "}"
           "QScrollBar::handle:vertical:hover {"
           "    background: lightGray; "
           "    min-height: 0px;"
           ""
           "}"
           "QScrollBar::handle:vertical {"
           "    background: darkGray; "
           "    min-height: 0px;"
           ""
           "}"
           "QScrollBar::add-line:vertical {"
           "    background: qlineargradient(x1:0, y1:0, x2:1, y2:0,"
           "    stop: 0  rgb(32, 47, 130), stop: 0.5 rgb(32, 47, 130),  stop:1 rgb(32, 47, 130));"
           "    height: px;"
           "    subcontrol-position: bottom;"
           "    subcontrol-origin: margin;"
           "}"
           "QScrollBar::sub-line:vertical {"
           "    background: qlineargradient(x1:0, y1:0, x2:1, y2:0,"
           "    stop: 0  rgb(32, 47, 130), stop: 0.5 rgb(32, 47, 130),  stop:1 rgb(32, 47, 130));"
           "    height: 0px;"
           "    subcontrol-position: top;"
           "    subcontrol-origin: margin;"
           "}"
           "QScrollBar:horizontal {"
           "    border: 0px solid darkGray; "
           "    background:%1;"
           "    width: 8px;    "
           "    margin: 1px 1px 1px 1px;"
           "}"
           "QScrollBar::handle:horizontal {"
           "    background: darkGray; "
           "    min-height: 0px;"
           ""
           "}"
           "QScrollBar::add-line:horizontal {"
           "    background: qlineargradient(x1:0, y1:0, x2:1, y2:0,"
           "    stop: 0  rgb(32, 47, 130), stop: 0.5 rgb(32, 47, 130),  stop:1 rgb(32, 47, 130));"
           "    height: px;"
           "    subcontrol-position: bottom;"
           "    subcontrol-origin: margin;"
           "}"
           "QScrollBar::sub-line:horizontal {"
           "    background: qlineargradient(x1:0, y1:0, x2:1, y2:0,"
           "    stop: 0  rgb(32, 47, 130), stop: 0.5 rgb(32, 47, 130),  stop:1 rgb(32, 47, 130));"
           "    height: 0px;"
           "    subcontrol-position: top;"
           "    subcontrol-origin: margin;"
           "}"
           "QTableWidget::item:hover { color: black; background: lightGray; }"
           "QTreeView::item:hover { color: black; background: lightGray; }"
           "").arg(GColor(CPLOTBACKGROUND).name())
#ifndef Q_OS_MAC
            .arg(GColor(CPLOTGRID).name())
            .arg(GCColor::alternateColor(GColor(CPLOTBACKGROUND)).name())
#endif
            ;
}

void
TabView::configChanged(qint32)
{
#if (defined Q_OS_LINUX) || (defined Q_OS_WIN)
    // style that sucker
    if (sidebar_) {
        sidebar_->setStyleSheet(ourStyleSheet());
    }
#endif
}

void
TabView::setPage(HomeWindow *page)
{
    page_ = page;

    // add to mainSplitter
    // now reset the splitter
    mainSplitter->insertWidget(-1, page);
    mainSplitter->setStretchFactor(0,0);
    mainSplitter->setCollapsible(0, false);
    splitter->insertWidget(-1, mainSplitter);

    // restore sizes
    QString setting = QString("%1/%2").arg(GC_SETTINGS_SPLITTER_SIZES).arg(type);
    QVariant splitterSizes = appsettings->cvalue(context->athlete->cyclist, setting); 

    // new (3.1) mechanism 
    if (splitterSizes.toByteArray().size() > 1 ) {
        splitter->restoreState(splitterSizes.toByteArray());
    } else {

        // use old (v3 or earlier) mechanism
        QVariant splitterSizes = appsettings->cvalue(context->athlete->cyclist, GC_SETTINGS_SPLITTER_SIZES); 
        if (splitterSizes.toByteArray().size() > 1 ) {

            splitter->restoreState(splitterSizes.toByteArray());

        } else {

            // sensible default as never run before!
            QList<int> sizes;

            sizes.append(200);
            sizes.append(context->mainWindow->width()-200);
            splitter->setSizes(sizes);
            
        }
    }
}

void
TabView::setBottom(QWidget *widget)
{
    bottom_ = widget;
    bottom_->hide();
    mainSplitter->insertWidget(-1, bottom_);
    mainSplitter->setCollapsible(1, true); // XXX we need a ComparePane widget ...
    mainSplitter->setStretchFactor(1,1);
}

void 
TabView::dragEvent(bool x)
{
    setShowBottom(x);
    context->mainWindow->setToolButtons(); // toolbuttons reflect show/hide status
}

// hide and show bottom - but with a little animation ...
void
TabView::setShowBottom(bool x) 
{
    // remember last height used when hidind
    if (!x && bottom_) lastHeight = bottom_->height();

    // basic version for now .. remembers and sets horizontal position precisely
    // adding animation should be easy from here


    if (bottom_) {
        if (x) {

            // set to the last value....
            bottom_->show();

            anim->setDuration(lastHeight * 3);
            anim->setEasingCurve(QEasingCurve(QEasingCurve::Linear));
            anim->setKeyValueAt(0,mainSplitter->maxhpos()-22);
            anim->setKeyValueAt(1,mainSplitter->maxhpos()-(lastHeight+22));
            anim->start();

        } else {

            // need a hide animator to hide on timeout
            //anim->setDuration(200);
            //anim->setEasingCurve(QEasingCurve(QEasingCurve::Linear));
            //anim->setKeyValueAt(0,mainSplitter->maxhpos()-(lastHeight+22));
            //anim->setKeyValueAt(1,mainSplitter->maxhpos()-22);
            //anim->start();

            bottom_->hide();
        }
    }
}

void
TabView::setBlank(BlankStatePage *blank)
{
    blank_ = blank;
    blank->hide();
    stack->insertWidget(1, blank); // blank state always at index 1

    // and when stuff happens lets check
    connect(blank, SIGNAL(closeClicked()), this, SLOT(checkBlank()));
    connect(context, SIGNAL(rideAdded(RideItem*)), this, SLOT(checkBlank()));
    connect(context, SIGNAL(rideDeleted(RideItem*)), this, SLOT(checkBlank()));
    connect(context, SIGNAL(configChanged(qint32)), this, SLOT(checkBlank()));
    connect(trainDB, SIGNAL(dataChanged()), this, SLOT(checkBlank()));

}


void
TabView::sidebarChanged()
{
    if (sidebar_ == NULL) return;

    if (sidebarEnabled()) {

        setUpdatesEnabled(false);

        sidebar_->show();

        // Restore sizes
        QString setting = QString("%1/%2").arg(GC_SETTINGS_SPLITTER_SIZES).arg(type);
        QVariant splitterSizes = appsettings->cvalue(context->athlete->cyclist, setting);
        if (splitterSizes.toByteArray().size() > 1 ) {
            splitter->restoreState(splitterSizes.toByteArray());
            splitter->setOpaqueResize(true); // redraw when released, snappier UI
        }

        // if it was collapsed we need set to at least 200
        // unless the mainwindow isn't big enough
        if (sidebar_->width()<10) {
            int size = width() - 200;
            if (size>200) size = 200;

            QList<int> sizes;
            sizes.append(size);
            sizes.append(width()-size);
            splitter->setSizes(sizes);
        }

        // if user moved us then tell ride navigator if
        // we are the analysis view
        // all a bit of a hack to stop the column widths from
        // being adjusted as the splitter gets resized and reset
        if (type == VIEW_ANALYSIS && active == false && context->tab->rideNavigator()->geometry().width() != 100)
            context->tab->rideNavigator()->setWidth(context->tab->rideNavigator()->geometry().width());
        setUpdatesEnabled(true);

    } else sidebar_->hide();
}

void
TabView::tileModeChanged()
{
    if (page_) page_->setStyle(isTiled() ? 2 : 0);
}

void
TabView::selectionChanged()
{
    // we got selected..
    if (isSelected()) {

        // or do we need to show blankness?
        if (isBlank() && blank_ && page_ && blank_->canShow()) {

            splitter->hide();
            blank()->show();

            stack->setCurrentIndex(1);

        } else if (blank_ && page_) {

            blank()->hide();
            splitter->show();

            emit onSelectionChanged(); // give view a change to prepare
            page()->selected(); // select the view

            stack->setCurrentIndex(0);
        }
    } else {

        emit onSelectionChanged(); // give view a change to clear

    }
}

void
TabView::resetLayout()
{
    if (page_) page_->resetLayout();
}

void
TabView::addChart(GcWinID id)
{
    if (page_) page_->appendChart(id);
}

void
TabView::checkBlank()
{
    selectionChanged(); // run through the code again
}
