/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "SkWidget.h"
#include "SkCanvas.h"
#include "SkInterpolator.h"
#include "SkTime.h"
#include "SkParsePaint.h"

#if 0
SkWidgetView::SkWidgetView(U32 flags) : SkView(flags)
{
}

SkWidgetView::~SkWidgetView()
{
}

const char* SkWidgetView::GetEventType()
{
	return "SkWidgetView";
}

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

class SkTextView::Interp {
public:
	Interp(const SkString& old, SkMSec now, SkMSec dur, AnimaDir dir) : fOldText(old), fInterp(1, 2)
	{
		SkScalar x = 0;
		fInterp.setKeyFrame(0, now, &x, 0);
		x = SK_Scalar1;
		if (dir == kBackward_AnimDir)
			x = -x;
		fInterp.setKeyFrame(1, now + dur, &x);
	}
	bool draw(SkCanvas* canvas, const SkString& newText, SkScalar x, SkScalar y, SkPaint& paint)
	{
		SkScalar scale;

		if (fInterp.timeToValues(SkTime::GetMSecs(), &scale) == SkInterpolator::kFreezeEnd_Result)
		{
			canvas->drawText(newText.c_str(), newText.size(), x, y, paint);
			return false;
		}
		else
		{
			U8 alpha = paint.getAlpha();
			SkScalar above, below;
			(void)paint.measureText(NULL, 0, &above, &below);
			SkScalar height = below - above;
			SkScalar dy = SkScalarMul(height, scale);
			if (scale < 0)
				height = -height;

			// draw the old
			paint.setAlpha((U8)SkScalarMul(alpha, SK_Scalar1 - SkScalarAbs(scale)));
			canvas->drawText(fOldText.c_str(), fOldText.size(), x, y - dy, paint);
			// draw the new
			paint.setAlpha((U8)SkScalarMul(alpha, SkScalarAbs(scale)));
			canvas->drawText(newText.c_str(), newText.size(), x, y + height - dy, paint);
			// restore the paint
			paint.setAlpha(alpha);
			return true;
		}
	}

private:
	SkString		fOldText;
	SkInterpolator	fInterp;
};

SkTextView::SkTextView(U32 flags) : SkView(flags), fInterp(NULL), fDoInterp(false)
{
	fMargin.set(0, 0);
}

SkTextView::~SkTextView()
{
	delete fInterp;
}

void SkTextView::getText(SkString* str) const
{
	if (str)
		str->set(fText);
}

void SkTextView::setText(const char text[], AnimaDir dir)
{
	if (!fText.equals(text))
	{
		SkString tmp(text);
		this->privSetText(tmp, dir);
	}
}

void SkTextView::setText(const char text[], size_t len, AnimaDir dir)
{
	if (!fText.equals(text))
	{
		SkString tmp(text, len);
		this->privSetText(tmp, dir);
	}
}

void SkTextView::setText(const SkString& src, AnimaDir dir)
{
	if (fText != src)
		this->privSetText(src, dir);
}

void SkTextView::privSetText(const SkString& src, AnimaDir dir)
{
	SkASSERT(fText != src);

	if (fDoInterp)
	{
		if (fInterp)
			delete fInterp;
		fInterp = new Interp(fText, SkTime::GetMSecs(), 500, dir);
	}
	fText = src;
	this->inval(NULL);
}

/////////////////////////////////////////////////////////////////

void SkTextView::getMargin(SkPoint* margin) const
{
	if (margin)
		*margin = fMargin;
}

void SkTextView::setMargin(const SkPoint& margin)
{
	if (fMargin != margin)
	{
		fMargin = margin;
		this->inval(NULL);
	}
}

void SkTextView::onDraw(SkCanvas* canvas)
{
	this->INHERITED::onDraw(canvas);

	if (fText.size() == 0)
		return;

	SkPaint::Align	align = fPaint.getTextAlign();
	SkScalar		x, y;

	switch (align) {
	case SkPaint::kLeft_Align:
		x = fMargin.fX;
		break;
	case SkPaint::kCenter_Align:
		x = SkScalarHalf(this->width());
		break;
	default:
		SkASSERT(align == SkPaint::kRight_Align);
		x = this->width() - fMargin.fX;
		break;
	}

	fPaint.measureText(NULL, 0, &y, NULL);
	y = fMargin.fY - y;

	if (fInterp)
	{
		if (fInterp->draw(canvas, fText, x, y, fPaint))
			this->inval(NULL);
		else
		{
			delete fInterp;
			fInterp = NULL;
		}
	}
	else
		canvas->drawText(fText.c_str(), fText.size(), x, y, fPaint);
}

//////////////////////////////////////////////////////////////////////////////////////

void SkTextView::onInflate(const SkDOM& dom, const SkDOM::Node* node)
{
	this->INHERITED::onInflate(dom, node);

	const char* text = dom.findAttr(node, "text");
	if (text)
		this->setText(text);

	SkPoint	margin;
	if (dom.findScalars(node, "margin", (SkScalar*)&margin, 2))
		this->setMargin(margin);
	(void)dom.findBool(node, "do-interp", &fDoInterp);

	SkPaint_Inflate(&fPaint, dom, node);
}

//////////////////////////////////////////////////////////////////////////////////////

SkSliderView::SkSliderView(U32 flags) : SkWidgetView(flags)
{
	fValue = 0;
	fMax = 0;
}

static U16 actual_value(U16CPU value, U16CPU max)
{
	return SkToU16(SkMax32(0, SkMin32(value, max)));
}

void SkSliderView::setMax(U16CPU max)
{
	if (fMax != max)
	{
		fMax = SkToU16(max);
		if (fValue > 0)
			this->inval(NULL);
	}
}

void SkSliderView::setValue(U16CPU value)
{
	if (fValue != value)
	{
		U16 prev = actual_value(fValue, fMax);
		U16 next = actual_value(value, fMax);

		fValue = SkToU16(value);
		if (prev != next)
		{
			this->inval(NULL);

			if (this->hasListeners())
			{
				SkEvent	evt;
				
				evt.setType(SkWidgetView::GetEventType());
				evt.setFast32(this->getSinkID());
				evt.setS32("sliderValue", next);
				this->postToListeners(evt);
			}
		}
	}
}

#include "SkGradientShader.h"

static void setgrad(SkPaint* paint, const SkRect& r)
{
	SkPoint	pts[2];
	SkColor	colors[2];

#if 0
	pts[0].set(r.fLeft, r.fTop);
	pts[1].set(r.fLeft + r.height(), r.fBottom);
#else
	pts[0].set(r.fRight, r.fBottom);
	pts[1].set(r.fRight - r.height(), r.fTop);
#endif
	colors[0] = SK_ColorBLUE;
	colors[1] = SK_ColorWHITE;

	paint->setShader(SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kMirror_TileMode))->unref();
}

void SkSliderView::onDraw(SkCanvas* canvas)
{
	this->INHERITED::onDraw(canvas);

	U16CPU value = SkMax32(0, SkMin32(fValue, fMax));

	SkRect	r;
	SkPaint	p;

	r.set(0, 0, this->width(), this->height());

	p.setAntiAliasOn(true);
	p.setStyle(SkPaint::kStroke_Style);
	p.setStrokeWidth(SK_Scalar1);
	r.inset(SK_Scalar1/2, SK_Scalar1/2);
	canvas->drawRect(r, p);

	if (fMax)
	{
		SkFixed percent = SkFixedDiv(value, fMax);
		
		r.inset(SK_Scalar1/2, SK_Scalar1/2);
		r.fRight = r.fLeft + SkScalarMul(r.width(), SkFixedToScalar(percent));
		p.setStyle(SkPaint::kFill_Style);
		setgrad(&p, r);
		canvas->drawRect(r, p);
	}

#if 0
	r.set(0, 0, this->width(), this->height());
	r.inset(SK_Scalar1, SK_Scalar1);
	r.inset(r.width()/2, 0);
	p.setColor(SK_ColorBLACK);
	canvas->drawLine(*(SkPoint*)&r.fLeft, *(SkPoint*)&r.fRight, p);
#endif
}

SkView::Click* SkSliderView::onFindClickHandler(SkScalar x, SkScalar y)
{
	return new Click(this);
}

bool SkSliderView::onClick(Click* click)
{
	if (fMax)
	{
		SkScalar percent = SkScalarDiv(click->fCurr.fX + SK_Scalar1, this->width() - SK_Scalar1*2);
		percent = SkMaxScalar(0, SkMinScalar(percent, SK_Scalar1));
		this->setValue(SkScalarRound(percent * fMax));
		return true;
	}
	return false;
}

#endif