//<copyright>
// 
// Copyright (c) 1993,94,95
// Institute for Information Processing and Computer Supported New Media (IICM),
// Graz University of Technology, Austria.
// 
//</copyright>

//<file>
//
// Name:        progrind.C
//
// Purpose:     implementation of class ProgressIndicator
//
// Created:     11 Apr 94   Michael Pichler
//
// Changed:     12 Apr 95   Michael Pichler
//
//
//</file>



#include "progrind.h"

#include "fieldb.h"
#include "glyphutil.h"
#include "progress.h"
#include "wtranslate.h"

#include <InterViews/background.h>
#include <InterViews/canvas.h>
#include <InterViews/color.h>
#include <InterViews/display.h>
#include <InterViews/layout.h>
#include <InterViews/session.h>
#include <InterViews/style.h>
#include <InterViews/telltale.h>
#include <InterViews/window.h>
#include <IV-look/button.h>
#include <IV-look/kit.h>
#include <OS/string.h>

// #include <iostream.h>


/********** ProgressBar **********/
// Progress with stop flag

class ProgressBar: public Progress
{
  public:
    ProgressBar (ProgressIndicator* pi)
    { pi_ = pi; }

    // ProgressBase
    int stop() const
    { return pi_->stopped (); }

  private:
    ProgressIndicator* pi_;
};



/********** ProgressIndicator **********/

declareActionCallback (ProgressIndicator)
implementActionCallback (ProgressIndicator)


 
void ProgressIndicator::init (
  HgLanguage::Language lang,
  unsigned numreadyfields, const float* rsizes, const char** ready,
  unsigned numworkingfields, const float* wsizes, const char** working,
  Action* stop, int listenstop
)
{
  WidgetKit& kit = *WidgetKit::instance ();
  const LayoutKit& layout = *LayoutKit::instance ();
  kit.begin_style ("ProgressIndicator");

  deck_ = new Deck (2);

  if (numreadyfields < 1)  // pathologic
  { numreadyfields = 1;
    rsizes = 0;
  }
  if (numworkingfields < 1)
  { numworkingfields = 1;
    wsizes = 0;
  }

  // "ready"
  numreadyfields_ = numreadyfields;
  PolyGlyph* readybox = WLayoutKit::phbox (WLayoutKit::AlignFlexible, numreadyfields, rsizes);
  // readyfield_ = new FieldBrowser (&kit, kit.style (), ready);  // old
  readyfield_ = new FieldBrowser* [numreadyfields];

  int i;  // gcc keeps loop-vars local
  for (i = 0;  i < numreadyfields;  i++)
  {
    readybox->append (
      readyfield_ [i] = new FieldBrowser (&kit, kit.style (), ready ? ready [i] : 0)
    );
  }

  // progressbar
  progressbar_ = new ProgressBar (this);

  // "stop"
  stopaction_ = stop;
  Resource::ref (stop);

  listenstop_ = listenstop;
  stopped_ = 0;  // stop flag

  if (listenstop == noStopButton)
    stopbutton_ = nil;  // no stop button at all
  else
  {
    // stop button sets stop flag and calls stop action
    stopbutton_ = kit.push_button (WTranslate::str (WTranslate::STOP, lang),
      new ActionCallback(ProgressIndicator) (this, &ProgressIndicator::stopButtonAction)
    );
    stopbutton_->state ()->set (TelltaleState::is_enabled, stop || listenstop);
    // button is enabled whenever stop action or listenstop is set
  }

  const Color* flat = lookupColor (kit.style (), Session::instance ()->default_display (), "flat");
  if (!flat)
    flat = kit.background ();

  // "working"
  numworkingfields_ = numworkingfields;
  PolyGlyph* workingbox = WLayoutKit::phbox (WLayoutKit::AlignFlexible, numworkingfields, wsizes);

  // workingfield_ = new FieldBrowser (&kit, kit.style (), working);  // old
  workingfield_ = new FieldBrowser* [numworkingfields];

  for (i = 0;  i < numworkingfields;  i++)
  {
    workingbox->append (
      workingfield_ [i] = new FieldBrowser (&kit, kit.style (), working ? working [i] : 0)
    );
  }

  // messageWidth and progressWidth need neither add up to 100 nor to 1.0 (see phbox)
  double messageWidth = 70;
  kit.style ()->find_attribute ("messageWidth", messageWidth);
  double progressWidth = 30;
  kit.style ()->find_attribute ("progressWidth", progressWidth);

  PolyGlyph* progressbox = WLayoutKit::phbox (
    WLayoutKit::AlignFlexible,
    workingbox,                                  messageWidth,
    new Background (layout.hspace (5.0), flat),  0,  // filler
    kit.inset_frame (progressbar_),              progressWidth
  );

  if (stopbutton_)
  { progressbox->append (new Background (layout.hspace (5.0), flat));  // filler
    progressbox->append (new Background (stopbutton_, flat));
  }

  deck_->append (readybox);
  deck_->append (progressbox);
  deck_->flip_to (READY);

  body (deck_);

  kit.end_style ();  // "ProgressIndicator"
} // init


ProgressIndicator::~ProgressIndicator ()
{
  Resource::unref (stopaction_);
  delete readyfield_;
  delete workingfield_;
  // everything else cleaned up by glyphs in body
}


Progress* ProgressIndicator::getProgressbar () const
{
  return progressbar_;
}


ProgressBase* ProgressIndicator::getProgressbase () const
{
  return progressbar_;
}


void ProgressIndicator::repairWindow ()
{
  // does immediate repair of damaged areas
  Canvas* can = canvas ();
  Window* win;

  if (can && (win = can->window ()))
  { win->repair ();
    win->display ()->flush ();
  }
}


void ProgressIndicator::readyState ()
{
  if (deck_->card () != READY)
  {
    deck_->flip_to (READY);
    reallocate ();
    redraw ();
    repairWindow ();
  }
}


void ProgressIndicator::workingState (float p)
{
  if (deck_->card () != WORKING)
  {
    progressbar_->set (p, 0);  // repair below
    deck_->flip_to (WORKING);
    reallocate ();
    redraw ();
    repairWindow ();  // redraw all
  }
  else
    progressbar_->set (p);
}


void ProgressIndicator::readyMessage (const char* msg, unsigned field)
{
  if (field < numreadyfields_)
  {
    readyfield_[field]->field (msg);  // redraws itself
    deck_->modified (READY);
    reallocate ();
  }
}


void ProgressIndicator::workingMessage (const char* msg, unsigned field)
{
  if (field < numworkingfields_)
  {
    workingfield_[field]->field (msg);  // redraws itself
    // reallocate necessary although FieldBrowser can use any allocation
    // modified calls necessary such that allocate is really done
    deck_->modified (WORKING);
    // workingbox_->modified (0);  // anachronism
    reallocate ();
    //  redraw ();  // only when progress bar is allowed to change size
  }
}


void ProgressIndicator::setProgress (float p, int repair)
{
  progressbar_->set (p, repair);
}


void ProgressIndicator::increaseProgress (float p, int repair)
{
  progressbar_->increase (p, repair);
}


float ProgressIndicator::getProgress () const
{
  return progressbar_->get ();
}


void ProgressIndicator::stopAction (Action* stop)
{
  Resource::ref (stop);
  Resource::unref (stopaction_);
  stopaction_ = stop;
  if (stopbutton_)
    stopbutton_->state ()->set (TelltaleState::is_enabled, stop || listenstop_);
}


void ProgressIndicator::listenStop (int flag)
{
  if (listenstop_ != flag)
  {
    listenstop_ = flag;
    if (stopbutton_)
      stopbutton_->state ()->set (TelltaleState::is_enabled, stopaction_ || flag);
  }
}


void ProgressIndicator::stopButtonAction ()
{
  if (listenstop_)
    stopped_ = 1;  // set flag for stopped ()

  if (stopaction_)
    stopaction_->execute ();
}
