/***************************************************************************
 *   Copyright (C) by                                                      *
 *     - 2005: Christian Leh <moodwrod@web.de>                             *
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include <kapplication.h>
#include <kconfig.h>
#include <kdebug.h>
#include <kgenericfactory.h>
#include <kglobalsettings.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>
#include <kuser.h>

#include <qlabel.h>
#include <qimage.h>
#include <qrect.h>
#include <qpainter.h>
#include <qstringlist.h>
#include <qwidget.h>
#include <qlayout.h>

#include "magiclabel.h"
#include "thememoodin.h"

K_EXPORT_COMPONENT_FACTORY(ksplashmoodin, KGenericFactory<ThemeMoodin>("ksplash"))


ThemeMoodin::ThemeMoodin(QWidget* parent, const char* name, const QStringList& args)
            :ThemeEngine(parent, name, args)
{
  readSettings();
  init();
}


void ThemeMoodin::readSettings()
{
  const QRect screen = kapp->desktop()->screenGeometry(mTheme->xineramaScreen());

  if (!mTheme)
    return;

  KConfig* cfg = mTheme->themeConfig();

  if (!cfg)
    return;

  cfg->setGroup(QString("KSplash Theme: %1").arg(mTheme->theme()));

  QFont defaultFont("Trebuchet MS", 10);
  QFont defaultStatusFont("Trebuchet MS", 12, QFont::Bold);
  QColor defaultColor(0xFF, 0xFF, 0xFF);
  QColor defaultShadowColor(0x6D, 0x6D, 0x6D);
  QPoint defaultPoint(-1, -1), defaultOffset(0, 0);
  QString defaultIcon;

  mCurrentStatusIndex = 0;
  mSplashRect = cfg->readRectEntry("SplashRect", &screen);
  mBackgroundImage = cfg->readEntry("Background", QString::null);
  mStatusColor = cfg->readColorEntry("StatusColor", &defaultColor);
  mStatusFont = cfg->readFontEntry("StatusFont", &defaultStatusFont);
  mStatusCoords = cfg->readPointEntry("StatusCoords", &defaultPoint);
  mLabelShadow = cfg->readBoolEntry("LabelShadow", true);
  mLabelShadowColor = cfg->readColorEntry("LabelShadowColor", &defaultShadowColor);
  mShowStatusText = cfg->readBoolEntry("ShowStatusText", true);
  mAnimationLength = cfg->readNumEntry("AnimationLength", 30);
  mAnimationDelay = cfg->readNumEntry("AnimationDelay", 30);
  mBeginOpacity = cfg->readDoubleNumEntry("BeginOpacity", 0.20);
  mUseIconSet = cfg->readBoolEntry("UseIconSet", true);
  mIconSetSize = cfg->readNumEntry("IconSetSize", 48);
  mAppendX = cfg->readBoolEntry("AppendX", true);
  mImageSpacer = cfg->readNumEntry("ImageSpacer", mUseIconSet ? mIconSetSize : 0);
  mUsersBackground = cfg->readBoolEntry("UsersBackground", false);
  mLabelCount = cfg->readNumEntry("Labels", 0);
  mLabelShadowOffset = cfg->readPointEntry("LabelShadowOffset", new QPoint(2, 2));
  mBaseResolution = cfg->readSizeEntry("BaseResolution", new QSize(1280, 1024));
  mTranslate = cfg->readBoolEntry("Translate", true);
  mLineUpImages = cfg->readBoolEntry("LineUpImages", false);

  for (int i = 0; i < int(statusPixmaps().count()); i++)
  {
    if (mUseIconSet)
      defaultIcon = statusPixmaps()[i];
    else
      defaultIcon = QString("%1.png").arg(i + 1);

    mStatusIcons.append(cfg->readEntry(QString("Image%1").arg(i + 1), defaultIcon));
    mStatusIconCoords.append(cfg->readPointEntry(QString("ImageCoords%1").arg(i + 1), &defaultPoint));
    mStatusImageOffsets.append(cfg->readPointEntry(QString("ImageOffset%1").arg(i + 1), &defaultOffset));
    mStatusMessages.append(cfg->readEntry(QString("StatusMessage%1").arg(i + 1), QString::null));
  }

  for (int i = 0; i < mLabelCount; i++)
  {
    mLabels.append(cfg->readEntry(QString("Label%1").arg(i + 1), QString::null));
    mLabelCoords.append(cfg->readPointEntry(QString("LabelCoords%1").arg(i + 1), &defaultPoint));
    mLabelFonts.append(cfg->readFontEntry(QString("LabelFont%1").arg(i + 1), &defaultFont));
    mLabelColors.append(cfg->readColorEntry(QString("LabelColor%1").arg(i + 1), &defaultColor));
  }
}


void ThemeMoodin::init()
{
  setBackgroundMode(NoBackground);
  setFixedSize(mSplashRect.size());

  mContainer = new QWidget(this);
  mContainer->setFixedSize(size());
  mScaler = new Scaler(mBaseResolution, size());
  mCache = new Cache(mScaler, mTheme->themeEngine(), mTheme->theme());
  mBG = new KPixmap();
  mBG->resize(size());

  QPainter p;
  p.begin(mBG);

  initBackground(&p);
  initLabels(&p);
  initEffectWidgets();

  p.end();

  move(mSplashRect.topLeft());
}


void ThemeMoodin::initBackground(QPainter* p)
{
  if (!p)
    return;

  QString bgImage;

  if (mUsersBackground)
  {
    KConfig kdesktoprc("kdesktoprc", true, false);
    kdesktoprc.setGroup("Background Common");
    int num = kdesktoprc.readNumEntry("DeskNum", 0);

    kdesktoprc.setGroup(QString("Desktop%1").arg(num));
    bgImage = kdesktoprc.readPathEntry("Wallpaper", QString::null);
  }
  else
  {
    if (!mBackgroundImage.isEmpty())
      bgImage = mTheme->locateThemeData(mBackgroundImage);
  }

  if (bgImage.isEmpty())
    bgImage = mTheme->locateThemeData(QString("Background-%1x%2.jpg").arg(width()).arg(height()));

  if (bgImage.isEmpty())
    bgImage = mTheme->locateThemeData("Background.jpg");

  if (bgImage.isEmpty())
  {
    KMessageBox::error(this, i18n("No background. Try to put a Background.jpg in theme folder"));
    return;
  }

  QImage* bg = mCache->cacheFile(bgImage);
  p->drawImage(0, 0, *bg);
  delete bg;
}


void ThemeMoodin::initLabels(QPainter* p)
{
  if ((mLabelCount == 0) || (!p))
    return;

  for (int i = 0; i < mLabelCount; i++)
  {
    QString s = mLabels[i];
    QPoint pt = mLabelCoords[i];
    QColor c = mLabelColors[i];
    QFont f = mLabelFonts[i];

    if (s.isNull() || s.isEmpty())
      continue;

    MagicLabel ml(s, mTranslate);
    s = ml.value();

    mScaler->scaleSize(&f);
    mScaler->autoCoords(&pt, f, s);

    p->setFont(f);

    if (mLabelShadow)
    {
      p->setPen(mLabelShadowColor);
      p->drawText(pt + mLabelShadowOffset, s);
    }

    p->setPen(c);
    p->drawText(pt, s);
  }
}


void ThemeMoodin::initEffectWidgets()
{
  EffectWidget::setBackgroundImage(new QImage(mBG->convertToImage()));
  EffectWidget *fadeWidget = 0;
  QImage *image = 0;
  int index = -1;

  for (QStringList::ConstIterator it = mStatusIcons.constBegin(); it != mStatusIcons.constEnd(); ++it)
  {
    index++;

    if (mUseIconSet)
    {
      if ((*it).isEmpty())
        continue;

      // TODO: use cache in iconset mode
      QPixmap* px = new QPixmap(DesktopIcon(*it, mIconSetSize));
      image = new QImage(px->convertToImage());
      mScaler->scaleSize(image);
    }
    else
    {
      QString name = mTheme->locateThemeData(*it);
 
      if (name.isEmpty())
        continue;
  
      image = mCache->cacheFile(name);
  
      if (image->isNull())
      {
        delete image;
        continue;
      }
    }

    fadeWidget = createEffectWidget(mContainer, image);
    mEffectWidgets.append(fadeWidget);
    mImages.append(image);
    arrangeWidget(fadeWidget, index);
  }

  for (EffectWidget *fw = mEffectWidgets.first(); fw; fw = mEffectWidgets.next())
    fw->updateCache();
}


void ThemeMoodin::arrangeWidget(QWidget* w, const int index)
{
  QPoint current(mStatusIconCoords[index]);

  if (mLineUpImages)
  {
    static bool first = true;

    if (first)
    {
      int hw = mAppendX ? width() : height();
      int hwi = mAppendX ? height() : width();
      int icons = mStatusIcons.count() * mIconSetSize;
      int spaces = (mStatusIcons.count() - 1) * mIconSetSize;// + int(float(mIconSetSize) * 0.5);
      int q = int((hwi - mIconSetSize) / 2);
      int r = int((hw - icons - spaces) / 2);
  
      int x = mAppendX ? r : q;
      int y = mAppendX ? q : r;
  
      current.setX(x);
      current.setY(y);
      first = false;
    }
    else
    {
      int x = mAppendX ? mIconSetSize * 2 : 0;
      int y = mAppendX ? 0 : mIconSetSize * 2;

      current = mStatusIconCoords[index - 1] + QPoint(x, y);     
    }
  }
  else
  {
    mScaler->autoCoords(&current, QSize(mIconSetSize, mIconSetSize));
    current += mStatusImageOffsets[index];
  }

  mStatusIconCoords[index] = current;
  w->move(current);
}


EffectWidget* ThemeMoodin::createEffectWidget(QWidget* parent, QImage* image)
{
  EffectWidget *fw = new EffectWidget(parent);

  fw->hide();
  fw->setBackgroundOrigin(QWidget::WindowOrigin);
  fw->setDelay(mAnimationDelay);
  fw->setSteps(mAnimationLength);
  fw->setFixedSize(image->size());
  fw->setImage(image);
  fw->setStart(mBeginOpacity);
  fw->show();

  return fw;
}


void ThemeMoodin::slotSetText(const QString& s)
{
  if (mShowStatusText)
  {
    if (!mStatusMessages[mCurrentStatusIndex].isNull())
      mCurrentAction = mStatusMessages[mCurrentStatusIndex];
    else
      mCurrentAction = s;
  }
}


void ThemeMoodin::slotSetPixmap(const QString& s)
{
  if (!mEffectWidgets.count() > 0)
    return;

  int n = statusPixmaps().findIndex(s);

  if (n == -1)
    return;

  mCurrentStatusIndex = n + 1;

  EffectWidget *fw = mEffectWidgets.at(n);

  if (fw)
    fw->start();

  repaint(false);
}


void ThemeMoodin::updateStatus()
{
  QPainter p;
  p.begin(mContainer);

  // use a copy, otherwise status messages move around
  QPoint pt = mStatusCoords;
  QFontMetrics fm(mStatusFont);
  QSize fmSize(fm.size(0L, mCurrentAction));
  
  mScaler->autoCoords(&pt, fmSize);

  p.setFont(mStatusFont);
  
  if (mLabelShadow)
  {
    p.setPen(mLabelShadowColor);
    p.drawText(pt + mLabelShadowOffset, mCurrentAction);
  }
  
  p.setPen(mStatusColor);
  p.drawText(pt, mCurrentAction);
  p.end();
}


void ThemeMoodin::paintEvent(QPaintEvent* pe)
{
  QRect r = pe->rect();

  bitBlt(mContainer, r.x(), r.y(), mBG, r.x(), r.y(), r.width(), r.height());

  if (mShowStatusText)
    updateStatus();
}

#include "thememoodin.moc"
