/*
 * 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 "SkWidgetViews.h"
#include "SkTextBox.h"

#ifdef SK_DEBUG
static void assert_no_attr(const SkDOM& dom, const SkDOM::Node* node, const char attr[])
{
    const char* value = dom.findAttr(node, attr);
    if (value)
        SkDebugf("unknown attribute %s=\"%s\"\n", attr, value);
}
#else
    #define assert_no_attr(dom, node, attr)
#endif

SkStaticTextView::SkStaticTextView()
{
    fMargin.set(0, 0);
    fMode = kFixedSize_Mode;
    fSpacingAlign = SkTextBox::kStart_SpacingAlign;

//    init_skin_paint(kStaticText_SkinEnum, &fPaint);
}

SkStaticTextView::~SkStaticTextView()
{
}

void SkStaticTextView::computeSize()
{
    if (fMode == kAutoWidth_Mode)
    {
        SkScalar width = fPaint.measureText(fText.c_str(), fText.size());
        this->setWidth(width + fMargin.fX * 2);
    }
    else if (fMode == kAutoHeight_Mode)
    {
        SkScalar width = this->width() - fMargin.fX * 2;
        int lines = width > 0 ? SkTextLineBreaker::CountLines(fText.c_str(), fText.size(), fPaint, width) : 0;

        this->setHeight(lines * fPaint.getFontSpacing() + fMargin.fY * 2);
    }
}

void SkStaticTextView::setMode(Mode mode)
{
    SkASSERT((unsigned)mode < kModeCount);

    if (fMode != mode)
    {
        fMode = SkToU8(mode);
        this->computeSize();
    }
}

void SkStaticTextView::setSpacingAlign(SkTextBox::SpacingAlign align)
{
    fSpacingAlign = SkToU8(align);
    this->inval(NULL);
}

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

void SkStaticTextView::setMargin(SkScalar dx, SkScalar dy)
{
    if (fMargin.fX != dx || fMargin.fY != dy)
    {
        fMargin.set(dx, dy);
        this->computeSize();
        this->inval(NULL);
    }
}

size_t SkStaticTextView::getText(SkString* text) const
{
    if (text)
        *text = fText;
    return fText.size();
}

size_t SkStaticTextView::getText(char text[]) const
{
    if (text)
        memcpy(text, fText.c_str(), fText.size());
    return fText.size();
}

void SkStaticTextView::setText(const SkString& text)
{
    this->setText(text.c_str(), text.size());
}

void SkStaticTextView::setText(const char text[])
{
    if (text == NULL)
        text = "";
    this->setText(text, strlen(text));
}

void SkStaticTextView::setText(const char text[], size_t len)
{
    if (!fText.equals(text, len))
    {
        fText.set(text, len);
        this->computeSize();
        this->inval(NULL);
    }
}

void SkStaticTextView::getPaint(SkPaint* paint) const
{
    if (paint)
        *paint = fPaint;
}

void SkStaticTextView::setPaint(const SkPaint& paint)
{
    if (fPaint != paint)
    {
        fPaint = paint;
        this->computeSize();
        this->inval(NULL);
    }
}

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

    if (fText.isEmpty())
        return;

    SkTextBox    box;

    box.setMode(fMode == kAutoWidth_Mode ? SkTextBox::kOneLine_Mode : SkTextBox::kLineBreak_Mode);
    box.setSpacingAlign(this->getSpacingAlign());
    box.setBox(fMargin.fX, fMargin.fY, this->width() - fMargin.fX, this->height() - fMargin.fY);
    box.draw(canvas, fText.c_str(), fText.size(), fPaint);
}

void SkStaticTextView::onInflate(const SkDOM& dom, const SkDOM::Node* node)
{
if (false) { // avoid bit rot, suppress warning
    this->INHERITED::onInflate(dom, node);

    int    index;
    if ((index = dom.findList(node, "mode", "fixed,auto-width,auto-height")) >= 0) {
        this->setMode((Mode)index);
    } else {
        assert_no_attr(dom, node, "mode");
    }

    if ((index = dom.findList(node, "spacing-align", "start,center,end")) >= 0) {
        this->setSpacingAlign((SkTextBox::SpacingAlign)index);
    } else {
        assert_no_attr(dom, node, "spacing-align");
    }

    SkScalar s[2];
    if (dom.findScalars(node, "margin", s, 2)) {
        this->setMargin(s[0], s[1]);
    } else {
        assert_no_attr(dom, node, "margin");
    }

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

    if ((node = dom.getFirstChild(node, "paint")) != NULL &&
        (node = dom.getFirstChild(node, "screenplay")) != NULL)
    {
// FIXME: Including inflate_paint causes Windows build to fail -- it complains
//  that SKListView::SkListView is undefined.
#if 0
        inflate_paint(dom, node, &fPaint);
#endif
    }
}
}