#include <qdropsite.h>
#include <qdragobject.h>
#include <qvbox.h>
#include <dcopclient.h>
#include <qtimer.h>

#include <ktoolbarbutton.h>
#include <kfiledialog.h>
#include <kiconloader.h>
#include <kaboutdata.h>
#include <kstatusbar.h>
#include <kstdaction.h>
#include <kaction.h>
#include <kdebug.h>
#include <kglobal.h>
#include <kapplication.h>
#include <klocale.h>
#include <kurl.h>
#include <kconfig.h>
#include <kcmdlineargs.h>
#include <kkeydialog.h>
#include <kedittoolbar.h>
#include <kparts/event.h>
#include <kmenubar.h>
#include <kfiledialog.h>		//ADDED
#include <klibloader.h>
#include <kmessagebox.h>

#include <stdlib.h>
#include "editor.h"
//#include "setupFxmenu.cpp"

// StatusBar field IDs
#define ID_LINE_COLUMN 1
#define ID_INS_OVR 2
#define ID_SEL_NORM_BLOCK 3
#define ID_MODIFIED 4
#define ID_GENERAL 5

#define RUNID 12
#define RUNICON "run"
#define FXICON "paren"
//icons for run and function menu

QPtrList<Kate::Document> docList; //documents

Editor::Editor (Kate::Document *doc)
{
  setMinimumSize(200,200);
  if (!initialGeometrySet())resize(640,400); 

  factory = KLibLoader::self()->factory( "libkatepart" );
  if (!doc) 
  {
    KTextEditor::Document *tmpDoc = (KTextEditor::Document *) factory->create (0L, "kate", "KTextEditor::Document");
    doc = (Kate::Document *)tmpDoc; //new doc with default path
    docList.append(doc);
  }
  setupEditWidget(doc);
  setupActions();
  setupStatusBar();
  setAcceptDrops(true);
  setXMLFile("editorui.rc");
  createShellGUI( true );
  guiFactory()->addClient( kateView );
  KParts::GUIActivateEvent ev( true );
  QApplication::sendEvent( kateView, &ev );
  // Read basic main-view settings, and set to autosave
  setAutoSaveSettings( "Editor Options" );      
  readConfig();
}


Editor::~Editor()
{
//  if (kateView->isLastView()) docList.remove((Kate::Document*)kateView->getDoc());
}

// Now send the data to Octave!
void Editor::runCMDS(int id)
{
    kateView->save();				//save case we crash
    QString *cmds = new QString("");
    cmds->append( kateView->getDoc()->text() );
    if(!kateView->getDoc()->isModified() )
	emit runBuffer( cmds );			//emit the buffer
}

void Editor::init()
{
  KToolBar *tb = toolBar("mainToolBar");
  if (tb)
  { 
    m_paShowToolBar->setChecked( !tb->isHidden() );
    const QString text = QString("Save and run (F5)");
    const QString icon=QString(RUNICON);
    const QString fxicon=QString(FXICON);
    
    KIconLoader::KIconLoader ic = KIconLoader::KIconLoader( icon );
    KIconLoader::KIconLoader fx = KIconLoader::KIconLoader( fxicon );

    const char *tbname="Run";
    KToolBar *tb2 = toolBar(tbname); //put run button onto a own toolbar :) else tb->insert..
    tb2->insertButton( ic.iconPath(icon, -1, false), RUNID, SIGNAL( clicked(int)), this, SLOT( runCMDS(int) ), 
				   true, text, -1, KGlobal::instance() );
			    //RUNID IS DEFINED ON TOP OF THIS FILE!
    //function menu
    const QString fxtext="Function list";
    fxmenu= new QPopupMenu();
    setupFxmenu(fxmenu);
    tb2->insertButton(fx.iconPath(fxicon,-1,false) , RUNID+1,fxmenu, true, fxtext,-1);
//    connect(fxmenu,SIGNAL(activated(int) ),this,SLOT(insertFunction(int) ) );
    
  }
  else 
    m_paShowToolBar->setEnabled(false);
    
  KStatusBar *sb = statusBar();
  if (sb) m_paShowStatusBar->setChecked( !sb->isHidden() );
    else m_paShowStatusBar->setEnabled(false);
  newCurPos();
  newStatus();
  kateView->setLineNumbersOn(true);		//we allways want linenumbers
  show();
}


void Editor::loadURL(const KURL &url)
{
  m_recentFiles->addURL( url );
  kateView->getDoc()->openURL(url);
}

bool Editor::queryClose()
{
  if (!kateView->isLastView()) return true;
  return kateView->canDiscard();
}

bool Editor::queryExit()
{
  writeConfig();
  kapp->config()->sync();
//  return true;
  delete this;		// here ??
}

void Editor::setupEditWidget(Kate::Document *doc)
{
  kateView = (Kate::View *)doc->createView (this, 0L);
  connect(kateView, SIGNAL(cursorPositionChanged()),this,SLOT(newCurPos()));
  connect(kateView, SIGNAL(newStatus()),this,SLOT(newStatus()));
  connect(kateView->getDoc(), SIGNAL(fileNameChanged()), this, SLOT(newCaption()));
  connect(kateView, SIGNAL(dropEventPass(QDropEvent *)), this, SLOT(slotDropEvent(QDropEvent *)));
  setCentralWidget(kateView);
}

void Editor::functions(){}
// setup File menu
void Editor::setupActions()
{
  KStdAction::print(this, SLOT(printDlg()), actionCollection());
  KStdAction::openNew( this, SLOT(slotNew()), actionCollection(), "file_new" );
  KStdAction::open( this, SLOT( slotOpen() ), actionCollection(), "file_open" );
  m_recentFiles = KStdAction::openRecent(this, SLOT(slotOpen_delayed1(const KURL&)), actionCollection());
  new KAction(i18n("New &View"), 0, this, SLOT(newView()), actionCollection(), "file_newView");
  // setup Settings menu
  m_paShowToolBar = KStdAction::showToolbar( this, SLOT( toggleToolBar() ), actionCollection() );
  m_paShowStatusBar = KStdAction::showStatusbar(this, SLOT(toggleStatusBar()), actionCollection());
  m_paShowPath = new KToggleAction(i18n("Sho&w Path"), 0, this, SLOT(newCaption()), actionCollection(), "set_showPath");
  KStdAction::quit(this, SLOT(slotClose()), actionCollection());
  KStdAction::keyBindings(this, SLOT(editKeys()), actionCollection());
  KStdAction::configureToolbars(this, SLOT(editToolbars()), actionCollection());
}

void Editor::setupStatusBar()
{
  KStatusBar *statusbar;
  statusbar = statusBar();
  statusbar->insertItem(" Line:000000 Col: 000 ", ID_LINE_COLUMN);
  statusbar->insertItem(" XXX ", ID_INS_OVR);
  statusbar->insertItem(" XXX ", ID_SEL_NORM_BLOCK);
  statusbar->insertFixedItem(" * ", ID_MODIFIED);
  statusbar->insertItem("", ID_GENERAL, 1);
  statusbar->setItemAlignment( ID_GENERAL, AlignLeft );
}

void Editor::slotSave()
{
    KURL url=KFileDialog::getSaveURL(QString::null,
	i18n("*.m *.oct *.txt|Matlab, Octave files"), this, i18n("Open File..."));
    if(!url.isEmpty())
    {
	setCaption("Newfile");
	kateView->saveAs();
    }
		  
}

void Editor::slotNew()
{
    kateView->flush();		//this will ask if we want to save changes first..
}
void Editor::slotOpen_delayed1(const KURL& url)
{
	delayedURL=url;
	QTimer::singleShot(0,this,SLOT(slotOpen_delayed2()));
}

void Editor::slotOpen_delayed2()
{
	slotOpen(delayedURL);
}

void Editor::slotOpen()
{
    KURL url=KFileDialog::getOpenURL(QString::null,
        i18n("*.m *.oct|Ocatave, Matlab files"), this, i18n("Open File..."));
    if(!url.isEmpty())
    {
	slotOpen( url);
    }	
}

// Called after user has selected a file (file is in url)
void Editor::slotOpen( const KURL& url )
{
  if ( url.isEmpty() )return;
  if ( kateView->getDoc()->isModified() )		//Ask if we want to save the current?
  {
    int want_save = KMessageBox::warningYesNoCancel(this,
        i18n("The current file has been modified.\n" "Do you want to save it?"),i18n("Warning"));
    switch(want_save)
    {
      case KMessageBox::Yes:
             kateView->save();
	     loadURL(url);
           break;
      case KMessageBox::No:
	     loadURL(url);		//no save then..
           break;
      case KMessageBox::Cancel:
           break;
      default:
           break;
    }
  }else{				//if we chose cancel this is skipped, thus no change to current!
	kateView->getDoc()->setEncoding(encoding);
	loadURL(url);
    }
}

void Editor::newView()
{
  Editor *t = new Editor((Kate::Document *)kateView->getDoc());
  t->readConfig();
  t->init();
}

void Editor::toggleToolBar()
{
  if( m_paShowToolBar->isChecked() )
    toolBar("mainToolBar")->show();
  else
    toolBar("mainToolBar")->hide();
}

void Editor::toggleStatusBar()
{
  if( m_paShowStatusBar->isChecked() )
    statusBar()->show();
  else
    statusBar()->hide();
}

void Editor::editKeys()
{
  KKeyDialog dlg;
  dlg.insert(actionCollection());
  if( kateView )
    dlg.insert(kateView->actionCollection());
  dlg.configure();
}

void Editor::editToolbars()
{
  KEditToolbar *dlg = new KEditToolbar(guiFactory());
  if (dlg->exec())
  {
      KParts::GUIActivateEvent ev1( false );
      QApplication::sendEvent( kateView, &ev1 );
      guiFactory()->removeClient( kateView );
      createShellGUI( false );
      createShellGUI( true );
      guiFactory()->addClient( kateView );
      KParts::GUIActivateEvent ev2( true );
      QApplication::sendEvent( kateView, &ev2 );
  }
  delete dlg;
}

void Editor::printNow()
{
  kateView->getDoc()->print ();
}

void Editor::printDlg()
{
  kateView->getDoc()->printDialog ();
}

void Editor::newCurPos()
{
  statusBar()->changeItem(i18n(" Line: %1 Col: %2 ")
    .arg(KGlobal::locale()->formatNumber(kateView->cursorLine()+1, 0))
    .arg(KGlobal::locale()->formatNumber(kateView->cursorColumn(), 0)),
    ID_LINE_COLUMN);
}

void Editor::newStatus()
{
  newCaption();
  bool readOnly = !kateView->getDoc()->isReadWrite();
  uint config = kateView->getDoc()->configFlags();
  bool block=kateView->getDoc()->blockSelectionMode();
  if (readOnly)
    statusBar()->changeItem(i18n(" R/O "),ID_INS_OVR);
  else
    statusBar()->changeItem(config & Kate::Document::cfOvr ? i18n(" OVR ") : i18n(" INS "),ID_INS_OVR);
  statusBar()->changeItem(kateView->getDoc()->isModified() ? " * " : "",ID_MODIFIED);
  statusBar()->changeItem(block ? i18n("BLK") : i18n(" NORM "),ID_SEL_NORM_BLOCK);
}

void Editor::newCaption()
{
  if (kateView->getDoc()->url().isEmpty()) {
    setCaption(i18n("Untitled"),kateView->getDoc()->isModified());
  } else {
    //set caption
    if ( m_paShowPath->isChecked() )
    {
       //File name shouldn't be too long - Maciek
       if (kateView->getDoc()->url().filename().length() > 200)
         setCaption(kateView->getDoc()->url().prettyURL().left(197) + "...",kateView->getDoc()->isModified());
       else
         setCaption(kateView->getDoc()->url().prettyURL(),kateView->getDoc()->isModified());
     }
      else
     {
       //File name shouldn't be too long - Maciek
       if (kateView->getDoc()->url().filename().length() > 200)
         setCaption("..." + kateView->getDoc()->url().fileName().right(197),kateView->getDoc()->isModified());
       else
         setCaption(kateView->getDoc()->url().fileName(),kateView->getDoc()->isModified());

    }

  }
}

void Editor::dragEnterEvent( QDragEnterEvent *event )
{
  event->accept(QUriDrag::canDecode(event));
}


void Editor::dropEvent( QDropEvent *event )
{
  slotDropEvent(event);
}


void Editor::slotDropEvent( QDropEvent *event )
{
  QStrList  urls;
  if (QUriDrag::decode(event, urls)) {
    kdDebug(13000) << "Editor:Handling QUriDrag..." << endl;
		QPtrListIterator<char> it(urls);
		for( ; it.current(); ++it ) {
      slotOpen( (*it) );
    }
  }
}

void Editor::slotEnableActions( bool enable )
{
    QValueList<KAction *> actions = actionCollection()->actions();
    QValueList<KAction *>::ConstIterator it = actions.begin();
    QValueList<KAction *>::ConstIterator end = actions.end();
    for (; it != end; ++it )(*it)->setEnabled( enable );

    actions = kateView->actionCollection()->actions();
    it = actions.begin();
    end = actions.end();
    for (; it != end; ++it )
        (*it)->setEnabled( enable );
}

//write config for editor on close
void Editor::slotClose()
{
    writeConfig();
    close();
}

//common config
void Editor::readConfig(KConfig *config)
{
  m_paShowPath->setChecked( config->readBoolEntry("ShowPath") );
  m_recentFiles->loadEntries(config, "Recent Files");
}


void Editor::writeConfig(KConfig *config)
{
  config->writeEntry("ShowPath",m_paShowPath->isChecked());
  m_recentFiles->saveEntries(config, "Recent Files");
}


//config file
void Editor::readConfig() 
{
  KConfig *config;
  config = kapp->config();
  config->setGroup("Editor Options");
  readConfig(config);
  kateView->getDoc()->readConfig();
  readProperties(config);
}


void Editor::writeConfig()
{
  KConfig *config;
  config = kapp->config();
  config->setGroup("Editor Options");
  writeConfig(config);
  kateView->getDoc()->writeConfig();
  saveGlobalProperties(config);
}


void Editor::readProperties(KConfig *config)
{
  readConfig(config);
  kateView->readSessionConfig(config);
}

void Editor::saveProperties(KConfig *config)
{
  writeConfig(config);
  config->writeEntry("DocumentNumber",docList.find((Kate::Document *)kateView->getDoc()) + 1);
  kateView->writeSessionConfig(config);
}

void Editor::saveGlobalProperties(KConfig *config) //save documents
{
  uint z;
  QString buf;
  Kate::Document *doc;

  config->setGroup("Number");
  config->writeEntry("NumberOfDocuments",docList.count());

  for (z = 1; z <= docList.count(); z++) {
     buf = QString("Document%1").arg(z);
     config->setGroup(buf);
     doc = (Kate::Document *) docList.at(z - 1);
     doc->writeSessionConfig(config);
  }
}

//F5 == save & run
bool Editor::eventFilter( QObject *o,QEvent *e)
{
 
    if(e->type() == QEvent::KeyPress)
    {

        QKeyEvent * ke = (QKeyEvent*) e;
        if ( ke->key() == Qt::Key_F5 ) 
	{
#ifdef DEBUG_S
	    qDebug("RUN now!");			//kate might be using F5 by default for reload!
#endif
	    runCMDS(1);
	    return true;
	}
	else
	    return false;
    }
    else
	return false;
}


// session management
void Editor::restore(KConfig *config, int n)
{
  if (kateView->isLastView() && !kateView->getDoc()->url().isEmpty()) { //in this case first view
    loadURL(kateView->getDoc()->url());
  }
  readPropertiesInternal(config, n);
  init();
}

void Editor::setupFxmenu(QPopupMenu *menu)
{
        menu->insertTearOffHandle(-1,-1);               //only first ?

	QString cmdfile= QDir::home().path()+"/.commands.lst";
#ifdef DEBUG_S
	qDebug(cmdfile.latin1() );
#endif
        QFile file( cmdfile);              //point to kdehome ...apps...koctav/commands.
	if(file.exists() )
	{
        if ( file.open( IO_ReadOnly ) )
        {
         QTextStream stream( &file );
         QString line;
         while ( !stream.eof() )
         {
            line = stream.readLine();           // line of text excluding '\n'
            fxEntry += line;
         }
        }
        //process all lines in lines
        //and insert them
        int id=0;
	bool first=true;
	for(QStringList::Iterator it = fxEntry.begin(); it !=fxEntry.end(); ++it )
        {
         const QString name=(*it);                      //label
         if( (*it).length() == 1)               //then this is a menu label
         {
          subPopup =new QPopupMenu();         //contents of menu
          menu->insertItem ( name,subPopup,-1,-1 );
	 }
        else    //this is a entry
        {
	 id=subPopup->insertItem ((*it), -1, -1 );    //entry 1 fxId contains the id of item
	 if(first)
	 {
	    first=false;
	    fxFirst =id;
	 }
	 subPopup->connectItem (id, this, SLOT( insertFunction(int) ) );
#ifdef DEBUG_S	 
	 qDebug("Menu id:" +QString::number(id)+" text: "+ subPopup->text(id) );	//divide id with id of first to get 1-N ? 
#endif	
	}
       }
      }
    file.close();
}
//insert the function selected

void Editor::insertFunction(int at)
{
    QString item=*fxEntry.at(abs(at-fxFirst)+1) ;		//|at-first|+1 , at-first is negative so abs,
    //insert item at cursor					//entries are allways +1, since first is label of menu A-Z
    kateView->insertText(item);
    
#ifdef DEBUG_S							//number is negative???? abs?	
    qDebug("selected item with id "+QString::number(abs(at-fxFirst)+1)+"name :"+ *fxEntry.at(abs(at-fxFirst)+1));
#endif    

}


syntax highlighted by Code2HTML, v. 0.9.1