/***************************************************************************
 *   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 <tdeapplication.h>
#include <tdeconfig.h>
#include <kdebug.h>
#include <kgenericfactory.h>
#include <tdeglobalsettings.h>
#include <kiconloader.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <kstandarddirs.h>
#include <kuser.h>

#include <tqlabel.h>
#include <tqimage.h>
#include <tqrect.h>
#include <tqpainter.h>
#include <tqstringlist.h>
#include <tqwidget.h>
#include <tqlayout.h>

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

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


ThemeMoodin::ThemeMoodin(TQWidget* parent, const char* name, const TQStringList& args)
            :ThemeEngine(parent, name, args)
{
  TDEGlobal::locale()->insertCatalogue( "ksplash-engine-moodin" );
  readSettings();
  init();
}


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

  if (!mTheme)
    return;

  TDEConfig* cfg = mTheme->themeConfig();

  if (!cfg)
    return;

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

  TQFont defaultFont("Trebuchet MS", 10);
  TQFont defaultStatusFont("Trebuchet MS", 12, TQFont::Bold);
  TQColor defaultColor(0xFF, 0xFF, 0xFF);
  TQColor defaultShadowColor(0x6D, 0x6D, 0x6D);
  TQPoint defaultPoint(-1, -1), defaultOffset(0, 0);
  TQString defaultIcon;

  mCurrentStatusIndex = 0;
  mSplashRect = cfg->readRectEntry("SplashRect", &screen);
  mBackgroundImage = cfg->readEntry("Background", TQString());
  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 TQPoint(2, 2));
  mBaseResolution = cfg->readSizeEntry("BaseResolution", new TQSize(1280, 1024));
  mTranslate = cfg->readBoolEntry("Translate", true);
  mLineUpImages = cfg->readBoolEntry("LineUpImages", false);
  mScaleIcons = cfg->readBoolEntry("ScaleIcons", false);
  mKubuntuStyle = cfg->readBoolEntry("KubuntuStyle", false);

  // so we can centre icons, JRiddell
  int iconX = mBaseResolution.width();
  int iconY = mBaseResolution.height();
  TQRect defaultScreen = kapp->desktop()->screenGeometry(0);
  float scaleRatioWidth = ((float)mBaseResolution.width()) / ((float)defaultScreen.width());
  // unused. float scaleRatioHeight = ((float)mBaseResolution.height()) / ((float)desktopWidget.height());

  iconX = iconX / 2;
  // first icon position calculated based on size and spacing
  // Edgy Dialog.png is off centre so take off random 8 pixels
  iconX = iconX - (int)((((mIconSetSize+mImageSpacer)*4) - 8) * scaleRatioWidth);
  // Edgy Dialog.png is off centre so add random 20 pixels
  iconY = (iconY / 2) + 20;

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

    mStatusIcons.append(cfg->readEntry(TQString("Image%1").arg(i + 1), defaultIcon));
    if (mKubuntuStyle) {
      TQPoint *mypoint;
      mypoint = new TQPoint((int)(iconX + (i * (mIconSetSize+mImageSpacer) * scaleRatioWidth)), iconY);
      mStatusIconCoords.append( *mypoint );
    } else {
      mStatusIconCoords.append(cfg->readPointEntry(TQString("ImageCoords%1").arg(i + 1), &defaultPoint));
    }
    mStatusImageOffsets.append(cfg->readPointEntry(TQString("ImageOffset%1").arg(i + 1), &defaultOffset));
    mStatusMessages.append(cfg->readEntry(TQString("StatusMessage%1").arg(i + 1), TQString()));
  }

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


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

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

  TQPainter p;
  p.begin(mBG);

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

  p.end();

  move(mSplashRect.topLeft());
}


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

  TQString bgImage;
  bool scaleBgImage;

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

    kdesktoprc.setGroup(TQString("Desktop%1").arg(num));
    bgImage = kdesktoprc.readPathEntry("Wallpaper", TQString());
    if (kdesktoprc.readPathEntry("WallpaperMode", TQString()) == "Scaled") {
      scaleBgImage = true;
    }
    else {
      scaleBgImage = false;
    }
  }
  else
  {
    if (!mBackgroundImage.isEmpty())
      bgImage = mTheme->locateThemeData(mBackgroundImage);
      scaleBgImage = false;
  }

  if (bgImage.isEmpty()) {
    bgImage = mTheme->locateThemeData(TQString("Background-%1x%2.jpg").arg(width()).arg(height()));
    scaleBgImage = false;
  }

  if (bgImage.isEmpty()) {
    bgImage = mTheme->locateThemeData("Background.jpg");
    scaleBgImage = true;
  }

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

  TQImage* bg = mCache->cacheFile(bgImage);
  if (scaleBgImage) {
    p->drawImage(0, 0, (*bg).scale(width(), height()));
  }
  else {
    p->drawImage(0, 0, *bg);
  }
  delete bg;

  if (mKubuntuStyle) {
    //central Dialogue, JRiddell
    TQImage* central = new TQImage( mTheme->locateThemeData("Dialog.png") );
    p->drawImage((mBG->width() / 2) - (462  / 2), (mBG->height() / 2) - (324  / 2), *central);
    delete central;
  }
}

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

  for (int i = 0; i < mLabelCount; i++)
  {
    TQString s = mLabels[i];
    TQPoint pt = mLabelCoords[i];
    TQColor c = mLabelColors[i];
    TQFont 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 TQImage(mBG->convertToImage()));
  EffectWidget *fadeWidget = 0;
  TQImage *image = 0;
  int index = -1;

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

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

      // TODO: use cache in iconset mode
      TQPixmap* px = new TQPixmap(DesktopIcon(*it, mIconSetSize));
      image = new TQImage(px->convertToImage());
      // JRiddell don't scale icons 
      if (!mKubuntuStyle && mScaleIcons) {
        mScaler->scaleSize(image);
      }
    }
    else
    {
      TQString 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(TQWidget* w, const int index)
{
  TQPoint 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] + TQPoint(x, y);     
    }
  }
  else
  {
    mScaler->autoCoords(&current, TQSize(mIconSetSize, mIconSetSize));
    current += mStatusImageOffsets[index];
  }

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


EffectWidget* ThemeMoodin::createEffectWidget(TQWidget* parent, TQImage* image)
{
  EffectWidget *fw = new EffectWidget(parent);

  fw->hide();
  fw->setBackgroundOrigin(TQWidget::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 TQString& s)
{
  if (mShowStatusText)
  {
    if (!mStatusMessages[mCurrentStatusIndex].isNull())
      mCurrentAction = mStatusMessages[mCurrentStatusIndex];
    else
      mCurrentAction = s;
  }
}


void ThemeMoodin::slotSetPixmap(const TQString& 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()
{
  TQPainter p;
  p.begin(mContainer);

  // use a copy, otherwise status messages move around
  TQPoint pt = mStatusCoords;
  TQFontMetrics fm(mStatusFont);
  TQSize 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(TQPaintEvent* pe)
{
  TQRect r = pe->rect();

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

  if (mShowStatusText)
    updateStatus();
}

#include "thememoodin.moc"
