/*
 * txtview.C - text viewer
 *
 * created:  6 May 1993
 *
 * changed:  1 Jun 1993
 *
 */


#include "txtview.h"
#include "delhand.h"

#include <IV-look/kit.h>
#include <InterViews/background.h>
#include <InterViews/character.h>
#include <InterViews/composition.h>
#include <InterViews/label.h>
#include <InterViews/layout.h>
#include <InterViews/monoglyph.h>
#include <InterViews/patch.h>
#include <InterViews/texcomp.h>
#include <InterViews/session.h>
#include <InterViews/style.h>
#include <InterViews/window.h>
#include <OS/file.h>
#include <OS/math.h>
#include <OS/string.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream.h>



// *** class DocumentView ***


class DocumentView : public MonoGlyph {
public:
    DocumentView(InputFile*, WidgetKit&, const LayoutKit&);
    virtual ~DocumentView();

    virtual Adjustable* adjustable() const;
private:
    Composition* page_;
    ScrollBox* box_;
    Glyph* begin_par_;
    Glyph* end_par_;
    Glyph* begin_line_;
    Glyph* end_line_;
    Glyph* word_space_;
    Glyph* interline_;
    Glyph* vfil_glue_;

    void add(const String&, WidgetKit&, const LayoutKit&);
};





// *** showtext ***


static ApplicationWindow* tvdlgwin = 0;
static MonoGlyph* v_center = 0;
static Patch* tvpatch = 0;
static Patch* scroll_patch = 0;


void showtext (const char* filename)
{
  if (!filename || !*filename)
    return;

  InputFile* file = InputFile::open (filename);
  if (file == nil)
  {
    cerr << "textviewer. error: cannot open file " << filename << '.' << endl;
    return;
  }

  WidgetKit& kit = *WidgetKit::instance ();
  const LayoutKit& layout = *LayoutKit::instance ();


  if (!tvdlgwin)  // create window on first call
  {
    Style* tvstyle = new Style (kit.style ());
    tvstyle->attribute ("name", "Hyper-G Text Viewer");  // Title
    tvstyle->attribute ("iconName", "Hyper-G Text");

    // v_center = layout.vcenter (view, 1.0);
    v_center = layout.vcenter (nil, 1.0);
    scroll_patch = new Patch (nil);  // a MonoGlyph for the scroll bar

    tvpatch = new Patch (
      layout.hbox (
        layout.margin (
          layout.variable_span(
            layout.natural_span(
              v_center,
              6*72.0, 9*72.0
            )
          ),
          20.0
        ),
        scroll_patch
      )
    );

    tvdlgwin = new ApplicationWindow (
      new Background (
        tvpatch,
        kit.background ()
      )
    );

    tvdlgwin->style (tvstyle);

    // delete handler
    SDeleteHandler* delhandler = new SDeleteHandler;
    tvdlgwin->wm_delete (delhandler);
  }

  DocumentView* view = new DocumentView (file, kit, layout);

  // put DocumentView into window
  v_center->body (view);
  scroll_patch->body (kit.vscroll_bar (view->adjustable()));

  tvpatch->redraw ();
  tvpatch->reallocate ();
  tvpatch->redraw ();

  tvdlgwin->map ();

} // showtext



// *** implementation of class DocumentView ***

DocumentView::DocumentView(
    InputFile* file, WidgetKit& kit, const LayoutKit& layout
) {
    const Font* f = kit.font();
    const Color* fg = kit.foreground();
    word_space_ = layout.spaces(2, 0.5, f, fg);
    interline_ = layout.vglue();
    vfil_glue_ = layout.vglue();

    String v("justify");
    kit.style()->find_attribute("alignment", v);

    if (v == "justify")
    {   begin_line_ = layout.vstrut(0);
	end_line_ = layout.strut(f);
	begin_par_ = layout.vstrut(0);
	end_par_ = layout.strut(f, 0, fil, 0);
    }
    else  // default: "left"
    {   begin_line_ = layout.vstrut(0);
	end_line_ = layout.strut(f, 0, fil, 0);
	begin_par_ = layout.vstrut(0);
	end_par_ = layout.strut(f, 0, fil, 0);
    }

    Resource::ref(begin_par_);
    Resource::ref(end_par_);
    Resource::ref(begin_line_);
    Resource::ref(end_line_);
    Resource::ref(word_space_);
    Resource::ref(interline_);
    Resource::ref(vfil_glue_);

    box_ = layout.vscrollbox();
    box_->small_scroll(Dimension_Y, 2);
    page_ = new LRComposition(
	box_, new TeXCompositor(10), nil, 6*72.0, fil, fil, file->length()
    );
    const char* data;
    for (;;) {
	int len = file->read(data);
	if (len <= 0) {
	    break;
	}
	add(String(data, len), kit, layout);
    }
    page_->append(vfil_glue_);
    page_->repair();
    body(page_);
}

DocumentView::~DocumentView() {
// cerr << "hello: DocumentView::~DocumentView()" << endl;
    Resource::unref(begin_par_);
    Resource::unref(end_par_);
    Resource::unref(begin_line_);
    Resource::unref(end_line_);
    Resource::unref(word_space_);
    Resource::unref(interline_);
    Resource::unref(vfil_glue_);
}

void DocumentView::add(
    const String& data, WidgetKit& kit, const LayoutKit& layout
) {
    const char* p = data.string();
    const char* end = p + data.length();
    const Font* f = kit.font();
    const Color* fg = kit.foreground();
    Glyph* g[256];
    for (int i = 0; i < 256; i++) {
	g[i] = new Character(i, f, fg);
    }

    Resource::unref(g['\n']);
    g['\n'] = layout.discretionary(
	PenaltyGood,
	end_par_,
	end_par_,
	layout.discretionary(0, interline_, vfil_glue_, nil, nil),
	begin_par_
    );

    Resource::unref(g[' ']);
    g[' '] = layout.discretionary(
	0,
	word_space_,
	end_line_,
	layout.discretionary(0, interline_, vfil_glue_, nil, nil),
	begin_line_
    );

    Resource::unref(g['\t']);
    // g['\t'] = layout.shape_of(g['M']);
    g['\t'] = new Label("        ", f, fg);

    page_->append(begin_par_);
    for (; p < end; p++) {
	page_->append(g[*((unsigned char*)p)]);
    }
}

Adjustable* DocumentView::adjustable() const {
    return box_;
}
