/*
  Copyright (C) 2006 Daniele Galdi <daniele.galdi@gmail.com>
  
  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 program 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 General Public License for more details.
  
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  
  02110-1301, USA.
*/

/* Project related */
#include "adblock.h"
#include "adblockdialogue.h"

/* Tde related */
#include <kgenericfactory.h>
#include <kdebug.h>
#include <kiconloader.h>
#include <klibloader.h>
#include <tdeparts/statusbarextension.h>
#include <tdehtml_part.h>
#include <tdehtml_settings.h>
#include <kstatusbar.h>
#include <kurllabel.h>
#include <kdialogbase.h>
#include <kurl.h>
#include <tdeconfig.h>
#include <tdemessagebox.h>
#include <kstandarddirs.h>
#include <tdepopupmenu.h>
#include <kcmultidialog.h>
#include <tdelocale.h>
#include <dom/html_document.h>
#include <dom/html_image.h>
#include <dom/html_inline.h>
#include <dom/html_misc.h>
#include <dom/html_element.h>
#include <dom/dom_doc.h>
#include <dom/dom_node.h>
using namespace DOM;

#include <tqpixmap.h>
#include <tqcursor.h>
#include <tqregexp.h>

typedef KGenericFactory<AdBlock> AdBlockFactory;
K_EXPORT_COMPONENT_FACTORY( libadblock, AdBlockFactory( "adblock" ) )

AdBlock::AdBlock(TQObject *parent, const char *name, const TQStringList &) :
    KParts::Plugin(parent, name),
    m_label(0), m_menu(0)
{
    m_part = dynamic_cast<TDEHTMLPart *>(parent);
    if(!m_part) { kdDebug() << "couldn't get TDEHTMLPart" << endl; return; }           

    m_menu = new TDEPopupMenu(m_part->widget());
    m_menu->insertTitle(i18n("Adblock"));
    m_menu->insertItem(i18n("Configure"), this, TQ_SLOT(showTDECModule()));
    m_menu->insertItem(i18n("Show Elements"), this, TQ_SLOT(showDialogue()));

    connect(m_part, TQ_SIGNAL(completed()), this, TQ_SLOT(initLabel()));
}

AdBlock::~AdBlock() 
{
    KParts::StatusBarExtension *statusBarEx = KParts::StatusBarExtension::childObject(m_part);
    
    if (!statusBarEx) { kdDebug() << "couldn't get KParts::StatusBarExtension" << endl; return; }
    
    statusBarEx->removeStatusBarItem(m_label);    

    delete m_menu;
}

void AdBlock::initLabel()
{ 
    if (m_label) return;

    KParts::StatusBarExtension *statusBarEx = KParts::StatusBarExtension::childObject(m_part);

    if (!statusBarEx) { kdDebug() << "couldn't get KParts::StatusBarExtension" << endl; return; }

    m_label = new KURLLabel(statusBarEx->statusBar());

    TDEIconLoader *loader = instance()->iconLoader();

    m_label->setFixedHeight(loader->currentSize(TDEIcon::Small));
    m_label->setSizePolicy(TQSizePolicy(TQSizePolicy::Fixed, TQSizePolicy::Fixed));
    m_label->setUseCursor(false);
    m_label->setPixmap(loader->loadIcon("filter", TDEIcon::Small));

    statusBarEx->addStatusBarItem(m_label, 0, false);    

    connect(m_label, TQ_SIGNAL(leftClickedURL()), this, TQ_SLOT(showDialogue()));
    connect(m_label, TQ_SIGNAL(rightClickedURL()), this, TQ_SLOT(contextMenu()));
}

void AdBlock::showDialogue()
{
    if (!m_part->settings()->isAdFilterEnabled())
    {
	KMessageBox::error(0,
                           i18n("Please enable Konqueror's Adblock"),
                           i18n("Adblock disabled"));

	return;
    } 

    AdElementList elements;
    fillBlockableElements(elements);

    AdBlockDlg *dialogue = new AdBlockDlg(m_part->widget(), elements);
    connect(dialogue, TQ_SIGNAL( notEmptyFilter(const TQString&) ), this, TQ_SLOT( addAdFilter(const TQString&) ));
    connect(dialogue, TQ_SIGNAL( cancelClicked() ), dialogue, TQ_SLOT( delayedDestruct() ));
    connect(dialogue, TQ_SIGNAL( closeClicked() ), dialogue, TQ_SLOT( delayedDestruct() ));
    dialogue->show();
}

void AdBlock::showTDECModule()
{
    KCMultiDialog* dialogue = new KCMultiDialog(m_part->widget());
    dialogue->addModule("tdehtml_filter");
    connect(dialogue, TQ_SIGNAL( cancelClicked() ), dialogue, TQ_SLOT( delayedDestruct() ));
    connect(dialogue, TQ_SIGNAL( closeClicked() ), dialogue, TQ_SLOT( delayedDestruct() ));
    dialogue->show();
}

void AdBlock::contextMenu()
{
    m_menu->popup(TQCursor::pos());
}

void AdBlock::fillBlockableElements(AdElementList &elements)
{
    fillWithHtmlTag(elements, "script", "src", "SCRIPT");
    fillWithHtmlTag(elements, "embed" , "src", "OBJECT");
    fillWithHtmlTag(elements, "object", "src", "OBJECT");    
    fillWithImages(elements);

    const TDEHTMLSettings *settings = m_part->settings();

    AdElementList::iterator it;
    for ( it = elements.begin(); it != elements.end(); ++it )
    {
	AdElement &element = (*it);
        if (settings->isAdFiltered( element.url() )) 
	{
	    element.setBlocked(true);
	}
    }
}

void AdBlock::fillWithImages(AdElementList &elements)
{
    HTMLDocument htmlDoc = m_part->htmlDocument();

    HTMLCollection images = htmlDoc.images();
    
    for (unsigned int i = 0; i < images.length(); i++)
    {
	HTMLImageElement image = static_cast<HTMLImageElement>( images.item(i) );
	
	DOMString src = image.src();

	TQString url = htmlDoc.completeURL(src).string();
	if (!url.isEmpty() && url != m_part->baseURL().url())
	{
	    AdElement element(url, "image", "IMG", false);
	    if (!elements.contains( element )) 
		elements.append( element);
	}
    }
}

void AdBlock::fillWithHtmlTag(AdElementList &elements, 
			      const DOMString &tagName, 
			      const DOMString &attrName,
			      const TQString &category)
{
    Document doc = m_part->document();

    NodeList nodes = doc.getElementsByTagName(tagName);        

    for (unsigned int i = 0; i < nodes.length(); i++)
    {
	Node node = nodes.item(i);
	Node attr = node.attributes().getNamedItem(attrName);

	DOMString src = attr.nodeValue();
	if (src.isNull()) continue;
		
	TQString url = doc.completeURL(src).string();
	if (!url.isEmpty() && url != m_part->baseURL().url())
	{
	    AdElement element(url, tagName.string(), category, false);
	    if (!elements.contains( element )) 
		elements.append( element);
	}
    }
}

void AdBlock::addAdFilter(const TQString &url)
{
    //FIXME hackish
    TDEHTMLSettings *settings = const_cast<TDEHTMLSettings *>(m_part->settings());
    settings->addAdFilter(url);
}

// ----------------------------------------------------------------------------

AdElement::AdElement() :
  m_url(0), m_category(0), m_type(0), m_blocked(false) {}

AdElement::AdElement(const TQString &url, const TQString &category,
		     const TQString &type, bool blocked) :
  m_url(url), m_category(category), m_type(type), m_blocked(blocked) {}

AdElement &AdElement::operator=(const AdElement &obj)
{
  m_blocked = obj.m_blocked;
  m_url = obj.m_url;
  m_category = obj.m_category;
  m_type = obj.m_type;

  return *this;
}

bool AdElement::operator==(const AdElement &obj)
{
    return m_url == obj.m_url; 
}

bool AdElement::isBlocked() const
{
  return m_blocked;
}

void AdElement::setBlocked(bool blocked)
{
    m_blocked = blocked;
}

const TQString &AdElement::url() const
{
  return m_url;
}

const TQString &AdElement::category() const
{
  return m_category;
}

const TQString &AdElement::type() const
{
  return m_type;
}

#include "adblock.moc"
