/*
 * Copyright (c) 2007-2008, Aconex.  All Rights Reserved.
 * 
 * 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.
 */
#include <QtCore/QEvent>
#include <QtCore/QDateTime>
#include <QtGui/QResizeEvent>
#include <qwt_plot_renderer.h>
#include <qwt_scale_draw.h>
#include <qwt_scale_widget.h>
#include <qwt_text.h>
#include <qwt_text_label.h>
#include "timeaxis.h"
#include "main.h"

#define DESPERATE 0

class TimeScaleDraw: public QwtScaleDraw
{
public:
    TimeScaleDraw(void) :QwtScaleDraw() { }
    virtual QwtText label(double v) const
    {
	struct tm tm;
	QString string;
	time_t seconds = (time_t)v;

	pmLocaltime(&seconds, &tm);
	string.sprintf("%02d:%02d:%02d", tm.tm_hour, tm.tm_min, tm.tm_sec);
	return string;
    }
    virtual void getBorderDistHint(const QFont &f, int &start, int &end) const
    {
	if (orientation() == Qt::Horizontal) {
	    start = 0;
	    end = 0;
	}
	else {
	    QwtScaleDraw::getBorderDistHint(f, start, end);
	}
    }
};

TimeAxis::TimeAxis(QWidget *parent) : QwtPlot(parent)
{
    clearScaleCache();
    setFocusPolicy(Qt::NoFocus);
}

void TimeAxis::init()
{
    enableAxis(xTop, false);
    enableAxis(yLeft, false);
    enableAxis(yRight, false);
    enableAxis(xBottom, true);

    setAutoReplot(false);
    setAxisFont(QwtPlot::xBottom, *globalFont);
    setAxisScaleDraw(QwtPlot::xBottom, new TimeScaleDraw());
    setAxisLabelAlignment(QwtPlot::xBottom, Qt::AlignHCenter | Qt::AlignBottom);
}

void TimeAxis::print(QPainter *qp, QRect &rect, bool transparent)
{
    QwtPlotRenderer renderer;

    if (transparent)
	renderer.setDiscardFlag(QwtPlotRenderer::DiscardBackground);
    renderer.render(this, qp, rect);
}

void TimeAxis::noArchiveSources()
{
    setAxisScale(QwtPlot::xBottom, 0, 1, 0);
    replot();
}

void TimeAxis::clearScaleCache()
{
    my.points = 0;
    my.delta = my.scale = 0.0;
}

double TimeAxis::scaleValue(double delta, int points)
{
    if (my.delta == delta && my.points == points)
	return my.scale;

    // divisor is the amount of space (pixels) set aside for one major label.
    int maxMajor = qMax(1, width() / 54);
    int maxMinor;

    my.scale = (1.0 / ((double)width() / (points * 8.0))) * 8.0; // 8.0 is magic
    my.scale *= delta;

    // This is a sliding scale which converts arbitrary steps into more
    // human-digestable increments - seconds, ten seconds, minutes, etc.
    if (my.scale <= 10.0) {
	maxMinor = 10;
    } else if (my.scale <= 20.0) {	// two-seconds up to 20 seconds
	my.scale = floor((my.scale + 1) / 2) * 2.0;
	maxMinor = 10;
    } else if (my.scale <= 60.0) {	// ten-secondly up to a minute
	my.scale = floor((my.scale + 5) / 10) * 10.0;
	maxMinor = 10;
    } else if (my.scale <= 600.0) {	// minutely up to ten minutes
	my.scale = floor((my.scale + 30) / 60) * 60.0;
	maxMinor = 10;
    } else if (my.scale < 3600.0) {	// 10 minutely up to an hour
	my.scale = floor((my.scale + 300) / 600) * 600.0;
	maxMinor = 6;
    } else if (my.scale < 86400.0) {	// hourly up to a day
	my.scale = floor((my.scale + 1800) / 3600) * 3600.0;	
	maxMinor = 24;
    } else {				// daily then on (60 * 60 * 24)
	my.scale = 86400.0;
	maxMinor = 10;
    }

#if DESPERATE
    console->post(PmChart::DebugForce, "TimeAxis::scaleValue"
		  " width=%d points=%d scale=%.2f delta=%.2f maj=%d min=%d\n",
		    width(), points, my.scale, delta, maxMajor, maxMinor);
#endif

    my.delta = delta;
    my.points = points;
    setAxisMaxMajor(xBottom, maxMajor);
    setAxisMaxMinor(xBottom, maxMinor);
    return my.scale;
}

//
// Update the time axis if width changes, idea is to display increased
// precision as more screen real estate becomes available.  scaleValue
// is the critical piece of code in implementing it, as it uses width().
//
void TimeAxis::resizeEvent(QResizeEvent *e)
{
    QwtPlot::resizeEvent(e);
    if (e->size().width() != e->oldSize().width()) {
	clearScaleCache();
	activeGroup->updateTimeAxis();
    }
}
