/*  This file is part of the TDE project
    Copyright (C) 2007-2008 Gökçen Eraslan <gokcen@pardus.org.tr>
    Copyright (C) 2008 Dirk Mueller <mueller@kde.org>
    Copyright (C) 2008 Daniel Nicoletti <dantti85-pk@yahoo.com.br>
    Copyright (C) 2008-2010 Dario Freddi <drf@kde.org>

    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 library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include "AuthDialog.h"
#include "AuthDialogWidget.h"

#include <tqlabel.h>
#include <tqprocess.h>
#include <tqpainter.h>

#include <kcombobox.h>
#include <kdebug.h>
#include <kiconloader.h>
#include <klineedit.h>
#include "kuniqueapplication.h"
#include <kurllabel.h>
#include <kuser.h>
#include <tdelocale.h>

#include <PolkitTQt/Authority>
#include <PolkitTQt/Details>

using namespace PolkitTQt;

AuthDialog::AuthDialog(const TQString &actionId, const TQString &message,
        const TQString &iconName, const PolkitTQt::Details &details,
        const Identity::List &identities) :
        KDialogBase(0, 0, true, TQString::null, Ok|Cancel|Details, Ok),
        m_authWidget(new AuthDialogWidget(this))
{
  setMainWidget(m_authWidget);

  if (message.isEmpty())
  {
    kdWarning() << "Could not get action message for action." << endl;
    m_authWidget->lblHeader->hide();
  }
  else
  {
    kdDebug() << "Message of action: " << message << endl;
    m_authWidget->lblHeader->setText("<h3>" + message + "</h3>");
    setCaption(message);
    m_message = message;
  }

  // loads the standard key icon
  TQPixmap icon = TDEGlobal::iconLoader()->loadIcon("password", TDEIcon::NoGroup,
          TDEIcon::SizeHuge, TDEIcon::DefaultState);
  // create a painter to paint the action icon over the key icon
  TQPainter painter(&icon);
  const int iconSize = icon.size().width();
  int overlaySize = 32;
  const TQPixmap pixmap = TDEGlobal::iconLoader()->loadIcon(iconName, TDEIcon::NoGroup,
          overlaySize, TDEIcon::DefaultState, 0, true);
  if (!pixmap.isNull())
  {
    // bottom right corner
    TQPoint startPoint = TQPoint(iconSize - overlaySize - 2, iconSize - overlaySize - 2);
    painter.drawPixmap(startPoint, pixmap);
  }

  setIcon(icon);
  m_authWidget->lblPixmap->setPixmap(icon);

  // find action description for actionId
  for (const ActionDescription &desc : Authority::instance()->enumerateActionsSync())
  {
    if (actionId == desc.actionId())
    {
      m_actionDescription = desc;
      kdDebug() << "Action description has been found" << endl;
      break;
    }
  }

  AuthDetails *detailsDialog = new AuthDetails(details, m_actionDescription, m_appname, this);
  setDetailsWidget(detailsDialog);

  m_authWidget->userCB->hide();
  m_authWidget->lePassword->setFocus();
  m_authWidget->errorMessageKTW->hide();

  // If there is more than 1 identity we will show the combobox for user selection
  if (identities.size() > 1)
  {
    connect(m_authWidget->userCB, TQ_SIGNAL(activated(int)),
            this, TQ_SLOT(on_userCB_currentIndexChanged(int)));
    createUserCB(identities);
  }
  else
  {
    m_authWidget->userCB->insertItem("");
    m_userData.append(identities[0].toString());
    m_authWidget->userCB->setCurrentItem(0);
  }
	on_userCB_currentIndexChanged(-1);
}

AuthDialog::~AuthDialog()
{
}

void AuthDialog::accept()
{
  // Do nothing, do not close the dialog. This is needed so that the dialog stays
  m_authWidget->lePassword->setEnabled(false);
  return;
}

void AuthDialog::setRequest(const TQString &request, bool requiresAdmin)
{
  kdDebug() << request << endl;
  Identity identity = adminUserSelected();
  if (request.startsWith("password:", false))
  {
		if (!identity.isValid())
		{
			m_authWidget->lblPassword->setText(i18n("Password for root:"));
		}
		else
		{
			if (!m_authWidget->userCB->isVisible())
			{
				TQString username = identity.toString().remove("unix-user:");
				m_authWidget->lblPassword->setText(i18n("Password for %1:").arg(username));
			}
			else
			{
				m_authWidget->lblPassword->setText(i18n("Password:"));
			}
		}
  }
  else if (request.startsWith("password or swipe finger:"), false)
  {
		if (!identity.isValid())
		{
			m_authWidget->lblPassword->setText(i18n("Password or swipe finger for root:"));
		}
		else
		{
			if (!m_authWidget->userCB->isVisible())
			{
				TQString username = identity.toString().remove("unix-user:");
				m_authWidget->lblPassword->setText(i18n("Password or swipe finger for %1:").arg(username));
			}
			else
			{
				m_authWidget->lblPassword->setText(i18n("Password or swipe finger:"));
			}
		}
  }
  else
  {
    m_authWidget->lblPassword->setText(request);
  }
}

void AuthDialog::setOptions()
{
  m_authWidget->lblContent->setText(i18n("An application is attempting to perform an action "
        "that requires privileges. Authentication is required to perform this action."));
}

void AuthDialog::createUserCB(const Identity::List &identities)
{
  /* if we've already built the list of admin users once, then avoid
   * doing it again.. (this is mainly used when the user entered the
   * wrong password and the dialog is recycled)
   */
  if (identities.count() && (m_authWidget->userCB->count() - 1) != identities.count())
  {
    // Clears the combobox in the case some user be added
    m_authWidget->userCB->clear();
    m_userData.clear();

    // Adds a Dummy user
    m_authWidget->userCB->insertItem(i18n("Select User"));
    m_userData.append(TQString::null);

    // For each user
    int index = 1; // Start at 1 because of the "Select User" entry
    int currentUserIndex = -1;
    const KUser currentUser;
    for (const Identity &identity : identities)
    {
      // First check to see if the user is valid
      kdDebug() << "User: " << identity.toString() << endl;
      const KUser user(identity.toString().remove("unix-user:"));
      if (!user.isValid())
      {
        kdWarning() << "User invalid: " << user.loginName() << endl;
        continue;
      }

      // Display user full Name if available
      TQString display;
      if (!user.fullName().isEmpty())
      {
        display = user.fullName() + " (" + user.loginName() + ")";
      }
      else
      {
        display = user.loginName();
      }
      m_authWidget->userCB->insertItem(display);
      m_userData.append(identity.toString());

      if (user == currentUser)
      {
        currentUserIndex = index;
      }
      ++index;
    }

    // Show the widget and set focus
    if (currentUserIndex != -1)
    {
      m_authWidget->userCB->setCurrentItem(currentUserIndex);
    }
    m_authWidget->userCB->show();
  }
}

Identity AuthDialog::adminUserSelected() const
{
  if (m_authWidget->userCB->currentItem() == -1)
  {
    return Identity();
  }

  TQString id = m_userData[m_authWidget->userCB->currentItem()];
  if (id.isEmpty())
  {
    return Identity();
  }
  return Identity::fromString(id);
}

void AuthDialog::on_userCB_currentIndexChanged(int /*index*/)
{
  Identity identity = adminUserSelected();
  // identity is now valid when "Select user" is selected
  if (!identity.isValid())
  {
    m_authWidget->lePassword->setEnabled(false);
		m_authWidget->lblPassword->setText(i18n("Password:"));
    m_authWidget->lblPassword->setEnabled(false);
    enableButtonOK(false);
  }
  else
  {
    m_authWidget->lePassword->setEnabled(true);
    m_authWidget->lblPassword->setEnabled(true);
    enableButtonOK(true);
    // We need this to restart the auth with the new user
    emit adminUserSelected(identity);
    // give password label focus
    m_authWidget->lePassword->setFocus();
  }
}

TQString AuthDialog::password() const
{
  return m_authWidget->lePassword->text();
}

void AuthDialog::authenticationFailure()
{
  TQFont bold = font();
  bold.setBold(true);
  m_authWidget->errorMessageKTW->setText(i18n("Authentication failure, please try again."));
  m_authWidget->errorMessageKTW->setFont(bold);
  m_authWidget->errorMessageKTW->show();
  m_authWidget->lePassword->setEnabled(true);
  m_authWidget->lePassword->clear();
  m_authWidget->lePassword->setFocus();
}

AuthDetails::AuthDetails(const Details &details, const ActionDescription &actionDescription,
        const TQString &appname, TQWidget *parent) : AuthDetailsWidget(parent)
{
  app_label->setText(appname);

  for (const TQString &key : details.keys())
  {
    int row = AuthDetailsWidgetLayout->numRows() + 1;

    TQLabel *keyLabel = new TQLabel(this);
    keyLabel->setText(key);
    AuthDetailsWidgetLayout->addWidget(keyLabel, row, 0);

    TQLabel *valueLabel = new TQLabel(this);
    valueLabel->setText(details.lookup(key));
    AuthDetailsWidgetLayout->addWidget(valueLabel, row, 1);
  }

  action_label->setText(actionDescription.description());

  TQString vendor    = actionDescription.vendorName();
  TQString vendorUrl = actionDescription.vendorUrl();

  if (!vendor.isEmpty())
  {
    vendorUL->setText(vendor);
    vendorUL->setTipText(vendorUrl);
    vendorUL->setURL(vendorUrl);
  }
  else if (!vendorUrl.isEmpty())
  {
    vendorUL->setText(vendorUrl);
    vendorUL->setTipText(vendorUrl);
    vendorUL->setURL(vendorUrl);
  }
  else
  {
    vendorL->hide();
    vendorUL->hide();
  }

  connect(vendorUL, TQ_SIGNAL(leftClickedURL(const TQString&)),
          TQ_SLOT(openUrl(const TQString&)));
}

void AuthDetails::openUrl(const TQString &url)
{
  kapp->invokeBrowser(url);
}

#include "AuthDialog.moc"

