/*
 * This file is part of the Polkit-tqt project
 * Copyright (C) 2009 Daniel Nicoletti <dantti85-pk@yahoo.com.br>
 * Copyright (C) 2009 Dario Freddi <drf@kde.org>
 * Copyright (C) 2009 Jaroslav Reznik <jreznik@redhat.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library 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 "polkit-tqt-gui-action.h"
#include "polkit-tqt-authority.h"
#include "polkit-tqt-subject.h"

#include <tqapplication.h>


namespace PolkitTQt
{

namespace Gui
{

//--------------------------------------
// Action::Private
//--------------------------------------

class Action::Private
{
  public:
    Private(Action *p);

    void updateAction();
    bool computePkResult();

    Action *parent;

    TQString actionId;
    Authority::Result pkResult;
    TQ_LONG targetPID;

    bool initiallyChecked;

    // states data
    bool      selfBlockedVisible;
    bool      selfBlockedEnabled;
    TQString  selfBlockedText;
    TQString  selfBlockedWhatsThis;
    TQString  selfBlockedToolTip;
    TQIconSet selfBlockedIconSet;

    bool      noVisible;
    bool      noEnabled;
    TQString  noText;
    TQString  noWhatsThis;
    TQString  noToolTip;
    TQIconSet noIconSet;

    bool      authVisible;
    bool      authEnabled;
    TQString  authText;
    TQString  authWhatsThis;
    TQString  authToolTip;
    TQIconSet authIconSet;

    bool      yesVisible;
    bool      yesEnabled;
    TQString  yesText;
    TQString  yesWhatsThis;
    TQString  yesToolTip;
    TQIconSet yesIconSet;
};

Action::Private::Private(Action *p) : parent(p), targetPID(getpid())
{
  initiallyChecked = false;

  // Set the default values
  selfBlockedVisible = true;
  selfBlockedEnabled = false;

  noVisible     = true;
  noEnabled     = false;

  authVisible   = true;
  authEnabled   = true;

  yesVisible    = true;
  yesEnabled    = true;
}

void Action::Private::updateAction()
{
  if (Authority::instance()->hasError())
  {
    return;
  }

  switch (pkResult)
  {
    default:
    case Authority::Unknown:
    case Authority::No:
    {
      ::tqt_cast<TQAction*>(parent)->setVisible(noVisible);
      ::tqt_cast<TQAction*>(parent)->setEnabled(noEnabled);
      ::tqt_cast<TQAction*>(parent)->setText(noText);
      if (!noWhatsThis.isNull())
      {
        ::tqt_cast<TQAction*>(parent)->setWhatsThis(noWhatsThis);
      }
      if (!noToolTip.isNull())
      {
        ::tqt_cast<TQAction*>(parent)->setToolTip(noToolTip);
      }
      ::tqt_cast<TQAction*>(parent)->setIconSet(noIconSet);
      break;
    }

    case Authority::Challenge:
    {
      ::tqt_cast<TQAction*>(parent)->setVisible(authVisible);
      ::tqt_cast<TQAction*>(parent)->setEnabled(authEnabled);
      ::tqt_cast<TQAction*>(parent)->setText(authText);
      if (!authWhatsThis.isNull())
      {
        ::tqt_cast<TQAction*>(parent)->setWhatsThis(authWhatsThis);
      }
      if (!authToolTip.isNull())
      {
        ::tqt_cast<TQAction*>(parent)->setToolTip(authToolTip);
      }
      ::tqt_cast<TQAction*>(parent)->setIconSet(authIconSet);
      break;
    }

    case Authority::Yes:
    {
      ::tqt_cast<TQAction*>(parent)->setVisible(yesVisible);
      ::tqt_cast<TQAction*>(parent)->setEnabled(yesEnabled);
      ::tqt_cast<TQAction*>(parent)->setText(yesText);
      if (!yesWhatsThis.isNull())
      {
        ::tqt_cast<TQAction*>(parent)->setWhatsThis(yesWhatsThis);
      }
      if (!yesToolTip.isNull())
      {
        ::tqt_cast<TQAction*>(parent)->setToolTip(yesToolTip);
      }
      ::tqt_cast<TQAction*>(parent)->setIconSet(yesIconSet);
      if (parent->isOn())
      {
        ::tqt_cast<TQAction*>(parent)->setOn(!initiallyChecked);
      }
      break;
    }
  }
  emit parent->dataChanged();
}

bool Action::Private::computePkResult()
{
  Authority::Result old_result;
  UnixProcessSubject subject(parent->targetPID());

  old_result = pkResult;
  pkResult = Authority::instance()->checkAuthorizationSync(actionId, subject, Authority::None);

  return old_result != pkResult;
}

//--------------------------------------
// Action
//--------------------------------------

Action::Action(const TQString &actionId, TQObject *parent) : TQAction(parent), d(new Private(this))
{
  // this must be called AFTER the values initialization
  setPolkitAction(actionId);

  // track the config changes to update the action
  connect(Authority::instance(), TQ_SIGNAL(configChanged()), this, TQ_SLOT(slotConfigChanged()));
}

Action::~Action()
{
  delete d;
}

bool Action::activate()
{
  switch (d->pkResult)
  {
    case Authority::Yes:
    case Authority::Challenge:
    {
      emit authorized();
      return true;
    }

    case Authority::No:
    default:
    {
      if (d->noEnabled)
      {
        /* If PolicyKit says no... and we got here.. it means
         * that the user set the property "no-enabled" to true..
         * Hence, they probably have a good reason for doing
         * this so do let the 'activate' signal propagate..
         */
        emit authorized();
        return true;
      }
      break;
    }
  }
  return false;
}

void Action::setChecked(bool checked)
{
  // We store this as initiallyChecked
  // to be able to undo changes in case the auth fails
  d->initiallyChecked = checked;
  TQAction::setOn(checked);
}

void Action::slotConfigChanged()
{
  if (d->computePkResult())
  {
    d->updateAction();
  }
}

TQ_LONG Action::targetPID() const
{
  if (d->targetPID != 0)
  {
    return d->targetPID;
  }
  else
  {
    return getpid();
  }
}

void Action::setTargetPID(TQ_LONG pid)
{
  d->targetPID = pid;

  d->computePkResult();
  d->updateAction();
}

bool Action::isAllowed() const
{
  return d->pkResult == Authority::Yes;
}

bool Action::is(const TQString &other) const
{
  return d->actionId == other;
}

void Action::revoke()
{
  /*TODO: implement it? no negative authorizations available, no authorization db*/
}

void Action::setText(const TQString &text, States states)
{
  if (states & All)
  {
    d->selfBlockedText = text;
    d->noText = text;
    d->authText = text;
    d->yesText = text;
  }
  else if (states & Auth)
  {
    d->authText = text;
  }
  else if (states & No)
  {
    d->noText = text;
  }
  else if (states & SelfBlocked)
  {
    d->selfBlockedText = text;
  }
  else if (states & Yes)
  {
    d->yesText = text;
  }

  d->updateAction();
}

TQString Action::text(Action::States state) const
{
  switch (state)
  {
    case Yes:
    {
      return d->yesText;
    }
    case No:
    {
      return d->noText;
    }
    case Auth:
    {
      return d->authText;
    }
    case SelfBlocked:
    {
      return d->selfBlockedText;
    }
    case None:
    {
      return TQAction::text();
    }
    default:
    {
      return TQString::null;
    }
  }
}

void Action::setToolTip(const TQString &toolTip, States states)
{
  if (states & All)
  {
    d->selfBlockedToolTip = toolTip;
    d->noToolTip = toolTip;
    d->authToolTip = toolTip;
    d->yesToolTip = toolTip;
  }
  else if (states & Auth)
  {
    d->authToolTip = toolTip;
  }
  else if (states & No)
  {
    d->noToolTip = toolTip;
  }
  else if (states & SelfBlocked)
  {
    d->selfBlockedToolTip = toolTip;
  }
  else if (states & Yes)
  {
    d->yesToolTip = toolTip;
  }

  d->updateAction();
}

TQString Action::toolTip(Action::States state) const
{
  switch (state)
  {
    case Yes:
    {
      return d->yesToolTip;
    }
    case No:
    {
      return d->noToolTip;
    }
    case Auth:
    {
      return d->authToolTip;
    }
    case SelfBlocked:
    {
      return d->selfBlockedToolTip;
    }
    case None:
    {
      return TQAction::toolTip();
    }
    default:
    {
      return TQString::null;
    }
  }
}

void Action::setWhatsThis(const TQString &whatsThis, States states)
{
  if (states & All)
  {
    d->selfBlockedWhatsThis = whatsThis;
    d->noWhatsThis = whatsThis;
    d->authWhatsThis = whatsThis;
    d->yesWhatsThis = whatsThis;
  }
  else if (states & Auth)
  {
    d->authWhatsThis = whatsThis;
  }
  else if (states & No)
  {
    d->noWhatsThis = whatsThis;
  }
  else if (states & SelfBlocked)
  {
    d->selfBlockedWhatsThis = whatsThis;
  }
  else if (states & Yes)
  {
    d->yesWhatsThis = whatsThis;
  }

  d->updateAction();
}

TQString Action::whatsThis(Action::States state) const
{
  switch (state)
  {
    case Yes:
    {
      return d->yesWhatsThis;
    }
    case No:
    {
      return d->noWhatsThis;
    }
    case Auth:
    {
      return d->authWhatsThis;
    }
    case SelfBlocked:
    {
      return d->selfBlockedWhatsThis;
    }
    case None:
    {
      return TQAction::whatsThis();
    }
    default:
    {
      return TQString::null;
    }
  }
}

void Action::setIconSet(const TQIconSet &iconset, States states)
{
  if (states & All)
  {
    d->selfBlockedIconSet = iconset;
    d->noIconSet = iconset;
    d->authIconSet = iconset;
    d->yesIconSet = iconset;
  }
  else if (states & Auth)
  {
    d->authIconSet = iconset;
  }
  else if (states & No)
  {
    d->noIconSet = iconset;
  }
  else if (states & SelfBlocked)
  {
    d->selfBlockedIconSet = iconset;
  }
  else if (states & Yes)
  {
    d->yesIconSet = iconset;
  }

  d->updateAction();
}

TQIconSet Action::iconSet(Action::States state) const
{
  switch (state)
  {
    case Yes:
    {
      return d->yesIconSet;
    }
    case No:
    {
      return d->noIconSet;
    }
    case Auth:
    {
      return d->authIconSet;
    }
    case SelfBlocked:
    {
      return d->selfBlockedIconSet;
    }
    case None:
    {
      return TQAction::iconSet();
    }
    default:
    {
      return TQIconSet();
    }
  }
}

void Action::setEnabled(bool enabled, States states)
{
  if (states & All)
  {
    d->selfBlockedEnabled = enabled;
    d->noEnabled = enabled;
    d->authEnabled = enabled;
    d->yesEnabled = enabled;
  }
  else if (states & Auth)
  {
    d->authEnabled = enabled;
  }
  else if (states & No)
  {
    d->noEnabled = enabled;
  }
  else if (states & SelfBlocked)
  {
    d->selfBlockedEnabled = enabled;
  }
  else if (states & Yes)
  {
    d->yesEnabled = enabled;
  }

  d->updateAction();
}

bool Action::isEnabled(Action::States state) const
{
  switch (state)
  {
    case Yes:
    {
      return d->yesEnabled;
    }
    case No:
    {
      return d->noEnabled;
    }
    case Auth:
    {
      return d->authEnabled;
    }
    case SelfBlocked:
    {
      return d->selfBlockedEnabled;
    }
    case None:
    {
      return TQAction::isEnabled();
    }
    default:
    {
      return false;
    }
  }
}

void Action::setVisible(bool visible, States states)
{
  if (states & All)
  {
    d->selfBlockedVisible = visible;
    d->noVisible = visible;
    d->authVisible = visible;
    d->yesVisible = visible;
  }
  else if (states & Auth)
  {
    d->authVisible = visible;
  }
  else if (states & No)
  {
    d->noVisible = visible;
  }
  else if (states & SelfBlocked)
  {
    d->selfBlockedVisible = visible;
  }
  else if (states & Yes)
  {
    d->yesVisible = visible;
  }

  d->updateAction();
}

bool Action::isVisible(Action::States state) const
{
  switch (state)
  {
    case Yes:
    {
      return d->yesVisible;
    }
    case No:
    {
      return d->noVisible;
    }
    case Auth:
    {
      return d->authVisible;
    }
    case SelfBlocked:
    {
      return d->selfBlockedVisible;
    }
    case None:
    {
      return TQAction::isVisible();
    }
    default:
    {
      return false;
    }
  }
}

void Action::setPolkitAction(const TQString &actionId)
{
  d->actionId = actionId;

  d->computePkResult();
  d->updateAction();
}

TQString Action::actionId() const
{
  return d->actionId;
}

}

}

#include "polkit-tqt-gui-action.moc"
