#include <../../nrnconf.h>
#if HAVE_IV  // to end of file

#include <ivstream.h>
#include <stdio.h>
#include <assert.h>

#include <InterViews/event.h>
#include <InterViews/hit.h>
#include <InterViews/canvas.h>
#include <InterViews/printer.h>
#include <InterViews/session.h>

#include <InterViews/monoglyph.h>
#include <InterViews/tformsetter.h>
#include <InterViews/layout.h>
#include <InterViews/style.h>
#include <IV-look/kit.h>
#include <InterViews/background.h>

#include "mymath.h"
#include "apwindow.h"
#include "ocglyph.h"
#include "scenevie.h"
#include "scenepic.h"
#include "rubband.h"
#include "idraw.h"

// XYView
/*static*/ class XYView_helper: public MonoGlyph {
  public:
    XYView_helper(Scene*, XYView*);
    virtual ~XYView_helper();
    virtual void request(Requisition&) const;
    virtual void allocate(Canvas*, const Allocation&, Extension&);
    virtual void draw(Canvas*, const Allocation&) const;
    virtual void print(Printer*, const Allocation&) const;
    virtual void pick(Canvas*, const Allocation&, int depth, Hit&);

  public:
    Transformer t_;

  private:
    XYView* v_;
    friend XYView* XYView::current_pick_view();
    friend XYView* XYView::current_draw_view();
    friend void XYView::current_pick_view(XYView*);
    static XYView* current_pick_view_;
    static XYView* current_draw_view_;
};

void XYView::current_pick_view(XYView* v) {
    XYView_helper::current_pick_view_ = v;
}

void print_t(const char* s, const Transformer& t) {
    float a00, a01, a10, a11, a20, a21;
    t.matrix(a00, a01, a10, a11, a20, a21);
    printf("%s transform %g %g %g %g %g %g\n", s, a00, a01, a10, a11, a20, a21);
}
XYView_helper::XYView_helper(Scene* s, XYView* v)
    : MonoGlyph(s) {
    v_ = v;
}
void XYView_helper::request(Requisition& req) const {
    Requirement rx(v_->width(), 0, 0, -v_->left() / v_->width());
    Requirement ry(v_->height(), 0, 0, -v_->bottom() / v_->height());
    req.require_x(rx);
    req.require_y(ry);
}

void XYView_helper::allocate(Canvas* c, const Allocation& a, Extension& ext) {
    t_ = c->transformer();
    // print_t("XYView_helper::allocate", t_);
    body()->allocate(c, a, ext);
}

void XYView_helper::draw(Canvas* c, const Allocation& a) const {
    current_draw_view_ = v_;
    ((XYView_helper*) this)->t_ = c->transformer();
    // print_t("XYView_helper::draw", c->transformer());
    v_->set_damage_area(c);
#if 0
	IfIdraw(pict(t_));
#else
    if (OcIdraw::idraw_stream) {
        Transformer tr(t_);
        tr.translate(3 * 72, 4 * 72);
        OcIdraw::pict(tr);
    }
#endif
    c->push_clipping();
    c->clip_rect(v_->left(), v_->bottom(), v_->right(), v_->top());
    body()->draw(c, a);
    c->pop_clipping();
    IfIdraw(end());
}

void XYView_helper::print(Printer* c, const Allocation&) const {
    current_draw_view_ = v_;
    c->push_clipping();
    c->clip_rect(v_->left(), v_->bottom(), v_->right(), v_->top());

    char buf[100];
    float x, b;
    v_->s2o().matrix(x, b, b, b, b, b);
    sprintf(buf, "\n%g setlinewidth", x);
    c->comment(buf);

    // when printfile started printing at the level of the xyview
    // the allocation was incorrect and was used by the background
    // that was ok when the background was white...
    // set the allocation the same as the clipping
    Allocation a1;
    Allotment ax(v_->left(), v_->width(), 0);
    Allotment ay(v_->bottom(), v_->height(), 0);
    a1.allot_x(ax);
    a1.allot_y(ay);

    body()->print(c, a1);
    c->pop_clipping();
}

void XYView_helper::pick(Canvas* c, const Allocation& a, int depth, Hit& h) {
    if (MyMath::inside(h.left(), h.bottom(), v_->left(), v_->bottom(), v_->right(), v_->top())) {
        if (h.event()->grabber()) {  // fixes a bug but I dont know why
#if 1
            // The above fix broke the handling of keystrokes for crosshairs and Rotate3D
            // It was needed so that buttons would appear normal when moving quickly from
            // a button through a box to a scene. Now we put in the right handler in
            // case event was a keystroke.
            if (h.event()->type() == Event::key) {
                h.target(depth, this, 0, h.event()->grabber());
            }
#endif
            return;
        }
        current_pick_view_ = v_;
        MonoGlyph::pick(c, a, depth, h);
        if (h.event()->type() == Event::down) {
#if 0
printf("XYView_helper hit (%g, %g)  event (%g, %g)\n", h.left(), h.bottom(),
h.event()->pointer_x(), h.event()->pointer_y());
printf(" allocation lb=(%g, %g), rt=(%g,%g)\n", a.left(), a.bottom(), a.right(), a.top());
#endif
        }
    }
}

static Coord pick_epsilon;
static void set_pick_epsilon() {
    pick_epsilon = 2;
}


XYView::XYView(Scene* s, Coord xsize, Coord ysize)
    : TransformSetter(new XYView_helper(s, this)) {
    init(s->x1(), s->y1(), s->x2() - s->x1(), s->y2() - s->y1(), s, xsize, ysize);
}

XYView::XYView(Coord x1, Coord y1, Coord xs, Coord ys, Scene* s, Coord xsize, Coord ysize)
    : TransformSetter(new XYView_helper(s, this)) {
    init(x1, y1, xs, ys, s, xsize, ysize);
}

void XYView::init(Coord x1, Coord y1, Coord xs, Coord ys, Scene* s, Coord xsize, Coord ysize) {
    set_pick_epsilon();
    xsize_orig_ = xsize;
    ysize_orig_ = ysize;
    csize(0., xsize, 0., ysize);
    origin(x1, y1);
    x_span(xs);
    y_span(ys);
    canvas(NULL);
    parent_ = NULL;  // not reffed
    append_view(s);
#if 0
	if (view_margin_ == fil) {
		Style* style = Session::instance()->style();
		if (!style->find_attribute("view_margin", view_margin_)) {
			view_margin_ = 0;
		}
		view_margin_ *= 72;
	}
#endif
}

Coord XYView::view_margin_ = fil;

XYView_helper::~XYView_helper() {
    if (v_ == current_pick_view_) {
        current_pick_view_ = NULL;
    }
    if (v_ == current_draw_view_) {
        current_draw_view_ = NULL;
    }
}

XYView::~XYView() {
    //	printf("~XYView\n");
    scene()->remove_view(this);
}

// should only be accessed by a method that traces its call from the pick
XYView* XYView::current_pick_view() {
    //	printf("current pick view %p\n", XYView_helper::current_pick_view_);
    return XYView_helper::current_pick_view_;
}

XYView* XYView_helper::current_pick_view_;

// should only be accessed by a method that traces its call from the draw
// or print
XYView* XYView::current_draw_view() {
    //	printf("current draw view %p\n", XYView_helper::current_draw_view_);
    return XYView_helper::current_draw_view_;
}

XYView* XYView_helper::current_draw_view_;

void XYView::append_view(Scene* s) {
    s->append_view(this);
}

void XYView::canvas(Canvas* c) {
    canvas_ = c;
}

void XYView::stroke(Canvas* c, const Color* color, const Brush* brush) {
    if (scene()->drawing_fixed_item()) {
        c->stroke(color, brush);
    } else {
        c->push_transform();
        c->transform(s2o());
        c->stroke(color, brush);
        c->pop_transform();
    }
}

Canvas* XYView::canvas() {
    return canvas_;
}

void XYView::undraw() {
    canvas_ = NULL;
    TransformSetter::undraw();
}

void XYView::damage(Glyph* g, const Allocation& a, bool fixed, bool vf) {
    if (canvas_) {
        Extension e;
        canvas_->push_transform();
        canvas_->transformer(((XYView_helper*) body())->t_);
        if (fixed) {
            Coord x, y;
            canvas_->transform(s2o());
            if (vf) {
                view_ratio(a.x(), a.y(), x, y);
            } else {
                s2o().inverse_transform(a.x(), a.y(), x, y);
            }
            Allocation a_fix = a;
            a_fix.x_allotment().origin(x);
            a_fix.y_allotment().origin(y);
            g->allocate(canvas_, a_fix, e);
        } else {
            g->allocate(canvas_, a, e);
        }
        // printf("damage extension %g %g %g %g\n", e.left(), e.bottom(), e.right(), e.top());
        // print_t("XYView::damage", canvas_->transformer());
        canvas_->pop_transform();
        canvas_->damage(e);
    }
}

void XYView::damage_all() {
    if (canvas_) {
        canvas_->damage(xc0_, yc0_, xc0_ + xsize_, yc0_ + ysize_);
    }
}

void XYView::damage(Coord x1, Coord y1, Coord x2, Coord y2) {
    if (canvas_) {
        Transformer& t = ((XYView_helper*) body())->t_;
        Coord tx1, ty1, tx2, ty2;
        t.transform(x1, y1, tx1, ty1);
        t.transform(x2, y2, tx2, ty2);
        const float off = canvas_->to_coord(1);
        tx1 = Math::max(tx1 - off, Coord(0));
        ty1 = Math::max(ty1 - off, Coord(0));
        tx2 = Math::min(tx2 + off, canvas_->width());
        ty2 = Math::min(ty2 + off, canvas_->height());
        canvas_->damage(tx1, ty1, tx2, ty2);
    }
}

void XYView::set_damage_area(Canvas* c) {
    Extension e;
    c->restrict_damage(0., 0., c->width(), c->height());
    c->damage_area(e);
    const float off = c->to_coord(1);
    c->transformer().inverse_transform(e.left() - off, e.bottom() - off, xd1_, yd1_);
    c->transformer().inverse_transform(e.right() + off, e.top() + off, xd2_, yd2_);
}

void XYView::damage_area(Coord& x1, Coord& y1, Coord& x2, Coord& y2) const {
    x1 = xd1_;
    y1 = yd1_;
    x2 = xd2_;
    y2 = yd2_;
}

void XYView::request(Requisition& req) const {
    TransformSetter::request(req);
    Requirement rx(xsize_orig_);
    Requirement ry(ysize_orig_);
    req.require_x(rx);
    req.require_y(ry);
}

void XYView::allocate(Canvas* c, const Allocation& a, Extension& ext) {
#ifdef MINGW
    if (a.y_allotment().span() <= 0. || a.x_allotment().span() <= 0.) {
        // a bug in mswindows iconify
        return;
    }
#endif
    if (canvas_ == NULL) {
        canvas_ = c;
    }
    c->push_transform();
    TransformSetter::allocate(c, a, ext);
    c->pop_transform();
}

void XYView::pick(Canvas* c, const Allocation& a, int depth, Hit& h) {
    canvas_ = c;
    c->push_transform();
    if (h.event()->type() == Event::down) {
#if 0
printf("XYView hit (%g, %g)  event (%g, %g)\n", h.left(), h.bottom(),
h.event()->pointer_x(), h.event()->pointer_y());
#endif
    }
    TransformSetter::pick(c, a, depth, h);
    c->pop_transform();
}

Scene* XYView::scene() const {
    return (Scene*) (((XYView_helper*) body())->body());
}

Coord XYView::left() const {
    return x1_;
}
Coord XYView::right() const {
    return x1_ + x_span_;
}
Coord XYView::bottom() const {
    return y1_;
}
Coord XYView::top() const {
    return y1_ + y_span_;
}
Coord XYView::width() const {
    return x_span_;
}
Coord XYView::height() const {
    return y_span_;
}

void XYView::view_ratio(float xrat, float yrat, Coord& x, Coord& y) const {
    x = xrat * xsize_ + xc0_;
    y = yrat * ysize_ + yc0_;
}

void XYView::ratio_view(Coord x, Coord y, float& xrat, float& yrat) const {
    xrat = (x - xc0_) / xsize_;
    yrat = (y - yc0_) / ysize_;
}

void XYView::size(Coord x1, Coord y1, Coord x2, Coord y2) {
    x1_ = Math::min(x1, x2);
    y1_ = Math::min(y1, y2);
    x_span_ = Math::abs(x2 - x1);
    y_span_ = Math::abs(y2 - y1);
    notify();
}

void XYView::origin(Coord x1, Coord y1) {
    x1_ = x1;
    y1_ = y1;
    notify();
}

void XYView::csize(Coord x0, Coord x, Coord y0, Coord y) const {
    XYView* v = (XYView*) this;
    v->xsize_ = x;
    v->ysize_ = y;
    v->xc0_ = x0;
    v->yc0_ = y0;
}

void XYView::box_size(Coord x1, Coord y1, Coord x2, Coord y2) {
    size(x1, y1, x2, y2);
}

void XYView::x_span(Coord x) {
    x_span_ = (x > 0) ? x : 1.;
    notify();
}
void XYView::y_span(Coord x) {
    y_span_ = (x > 0) ? x : 1.;
    notify();
}


void XYView::zout(Coord& x1, Coord& y1, Coord& x2, Coord& y2) const {
    Coord dx, dy;
    x1 = left();
    x2 = right();
    y1 = bottom();
    y2 = top();
    dx = .1 * (x2 - x1);
    dy = .1 * (y2 - y1);
    x1 -= dx;
    x2 += dx;
    y1 -= dy;
    y2 += dy;
}
void XYView::zin(Coord& x1, Coord& y1, Coord& x2, Coord& y2) const {
    Coord dx, dy;
    x1 = left();
    x2 = right();
    y1 = bottom();
    y2 = top();
    dx = .1 / 1.2 * (x2 - x1);
    dy = .1 / 1.2 * (y2 - y1);
    x1 += dx;
    x2 -= dx;
    y1 += dy;
    y2 -= dy;
}

void XYView::save(ostream& o) {
    PrintableWindow* w;
    if (!canvas_) {
        if (!parent() || !parent()->has_window()) {
            return;
        }
        w = parent()->window();
    } else {
        w = (PrintableWindow*) canvas()->window();
    }
    char buf[256];
    Coord x1, y1, x2, y2;
    zin(x1, y1, x2, y2);
    sprintf(buf,
            "{save_window_.view(%g, %g, %g, %g, %g, %g, %g, %g)}",
            x1,
            y1,
            x2 - x1,
            y2 - y1,
            w->save_left(),
            w->save_bottom(),
            xsize_,
            ysize_);
    o << buf << endl;
}

void XYView::scene2view(const Allocation& a) const {
    float m00 = width() / a.x_allotment().span();
    float m11 = height() / a.y_allotment().span();

    // takes a canvas transformation from scene to parent glyph coordinates
    // transforms vectors from original to xyview
    XYView* xyv = (XYView*) this;
    xyv->scene2viewparent_ =
        Transformer(m00, 0, 0, m11, left() - a.left() * m00, bottom() - a.bottom() * m11);
    // print_t("scene2view", scene2viewparent_);
}

void XYView::transform(Transformer& t, const Allocation& a, const Allocation& n) const {
#if 0
	Allotment ax, ay;
	if (view_margin()) {
		const Allotment& alx = a.x_allotment();
		ax.span(alx.span() - 2*view_margin());
		ax.origin(alx.begin() + view_margin());
		ax.alignment(0);
		const Allotment& aly = a.y_allotment();
		ay.span(aly.span() - 2*view_margin());
		ay.origin(aly.begin() + view_margin());
		ay.alignment(0);
	}else{
		ax = a.x_allotment();
		ay = a.y_allotment();
	}
	Allocation al;
	al.allot_x(ax);
	al.allot_y(ay);
	scene2view(al);
#else
    scene2view(a);
    const Allotment& ax = a.x_allotment();
    const Allotment& ay = a.y_allotment();
#endif
    const Allotment& nx = n.x_allotment();
    const Allotment& ny = n.y_allotment();
    XYView* v = (XYView*) this;
    csize(ax.begin(), ax.span(), ay.begin(), ay.span());
    float sx = xsize_ / width();
    float sy = ysize_ / height();
    XYView* xv = (XYView*) this;
    xv->x_pick_epsilon_ = pick_epsilon / sx;
    xv->y_pick_epsilon_ = pick_epsilon / sy;
    t.translate(-left(), -bottom());
    t.scale(sx, sy);
    t.translate(ax.begin(), ay.begin());
#if 0
printf("XYView::transform ax origin=%g span=%g alignment=%g begin=%g\n",
ax.origin(), ax.span(), ax.alignment(), ax.begin());
printf("XYView::transform ay origin=%g span=%g alignment=%g begin=%g %g\n",
ay.origin(), ay.span(), ay.alignment(), ay.begin(), ay.end());
printf("XYView::transform natx origin=%g span=%g alignment=%g begin=%g\n",
nx.origin(), nx.span(), nx.alignment(), nx.begin());
printf("XYView::transform naty origin=%g span=%g alignment=%g begin=%g %g\n",
ny.origin(), ny.span(), ny.alignment(), ny.begin(), ny.end());
#endif
}

// View
View::View(Scene* s)
    : XYView(s, s->x2() - s->x1(), s->y2() - s->y1()) {
    x_span_ = XYView::width();
    y_span_ = XYView::height();
}
View::View(Coord x, Coord y, Coord span, Scene* s, Coord xsize, Coord ysize)
    : XYView(x - span / 2., y - (ysize / xsize) * span / 2., span, span, s, xsize, ysize) {
    x_span_ = XYView::width();
    y_span_ = XYView::height();
}
View::View(Coord x1, Coord y1, Coord xs, Coord ys, Scene* s, Coord xsize, Coord ysize)
    : XYView(x1, y1, xs, ys, s, xsize, ysize) {
    x_span_ = XYView::width();
    y_span_ = XYView::height();
}
View::~View() {}

void View::origin(Coord x, Coord y) {
    XYView::origin(x - XYView::width() / 2., y - XYView::height() / 2.);
}

void View::box_size(Coord x1, Coord y1, Coord x2, Coord y2) {
    Coord w = x2 - x1;
    Coord h = y2 - y1;
    Coord magx = w / x_span_;
    Coord magy = h / y_span_;
    if (magx > magy) {
        x_span_ *= magx;
        y_span_ *= magx;
    } else {
        x_span_ *= magy;
        y_span_ *= magy;
    }
    x_span(x_span_);
    y_span(y_span_);
    origin((x1 + x2) / 2, (y1 + y2) / 2);
}

Coord View::x() const {
    return left() + XYView::width() / 2.;
}
Coord View::y() const {
    return bottom() + XYView::height() / 2.;
}
Coord View::view_width() const {
    return x_span_;
}
Coord View::view_height() const {
    return y_span_;
}

void View::transform(Transformer& t, const Allocation& a, const Allocation&) const {
    scene2view(a);
    const Allotment& ax = a.x_allotment();
    const Allotment& ay = a.y_allotment();
    csize(ax.begin(), ax.span(), ay.begin(), ay.span());
    float sx = ax.span() / XYView::width();
    float sy = ay.span() / XYView::height();
    //	if (sx > sy) sx = sy;
    t.translate(-x(), -y());
    t.scale(sx, sx);
    View* v = (View*) this;
    v->x_pick_epsilon_ = pick_epsilon / sx;
    v->y_pick_epsilon_ = pick_epsilon / sx;
    t.translate((ax.begin() + ax.end()) / 2, (ay.begin() + ay.end()) / 2);
    // printf("\nx origin=%g span=%g alignment=%g begin=%g end=%g\n", ax.origin(), ax.span(),
    // ax.alignment(), ax.begin(), ax.end()); printf("\ny origin=%g span=%g alignment=%g begin=%g
    // end=%g\n", ay.origin(), ay.span(), ay.alignment(), ay.begin(), ay.end());
    Coord x1, y1;
    t.transform(x() - x_span_ / 2, y() - y_span_ / 2, x1, y1);
    if (!Math::equal(ax.begin(), x1, 1) || !Math::equal(ay.begin(), y1, 1)) {
        t.inverse_transform(ax.begin(), ay.begin(), x1, y1);
        v->x_span_ = 2 * (x() - x1);
        v->y_span_ = 2 * (y() - y1);
        v->size(x1, y1, x1 + v->x_span_, y1 + v->y_span_);
    }
}

void XYView::move_view(Coord dx1, Coord dy1) {
    //	printf("move by %g %g \n", dx1, dy1);
    Coord x0, x1, y0, y1;
    Coord dx = Math::abs(dx1);
    Coord dy = Math::abs(dy1);
    if (dx < .9 * dy) {
        dx = 0.;
        dy = dy1;
    } else if (dy < .9 * dx) {
        dx = dx1;
        dy = 0.;
    } else {
        dx = dx1;
        dy = dy1;
    }
    s2o().transform(0, 0, x0, y0);
    s2o().transform(dx, dy, x1, y1);
    x0 = x0 - x1 + left();
    y0 = y0 - y1 + bottom();
    x1 = x0 + width();
    y1 = y0 + height();

#if 1
    if (dx > 0) {
        MyMath::round(x0, x1, MyMath::Higher, 4);
    } else {
        MyMath::round(x0, x1, MyMath::Lower, 4);
    }
    if (dy > 0) {
        MyMath::round(y0, y1, MyMath::Higher, 4);
    } else {
        MyMath::round(y0, y1, MyMath::Lower, 4);
    }
#endif

    XYView::origin(x0, y0);
    damage_all();
}

void View::move_view(Coord dx, Coord dy) {
    XYView::move_view(dx, dy);
}


void XYView::scale_view(Coord xorg, Coord yorg, float dxscl, float dyscl) {
    Coord x0, y0, l, b, r, t;
    Coord dx = Math::abs(dxscl);
    Coord dy = Math::abs(dyscl);
    if (dx < .9 * dy) {
        dx = 0.;
        dy = dyscl;
    } else if (dy < .9 * dx) {
        dx = dxscl;
        dy = 0.;
    } else {
        dx = dxscl;
        dy = dyscl;
    }
    s2o().transform(xorg, yorg, x0, y0);
    // printf("org %g %g %g %g\n", xorg, yorg, x0, y0);
    l = -(left() - x0) * dx + left();
    b = -(bottom() - y0) * dy + bottom();
    r = -(right() - x0) * dx + right();
    t = -(top() - y0) * dy + top();
#if 1
    if (dxscl > 1) {
        MyMath::round(l, r, MyMath::Expand, 4);
    } else {
        MyMath::round(l, r, MyMath::Contract, 4);
    }
    if (dyscl > 1) {
        MyMath::round(b, t, MyMath::Expand, 4);
    } else {
        MyMath::round(b, t, MyMath::Contract, 4);
    }
#endif
    size(l, b, r, t);
    damage_all();
}

void View::scale_view(Coord xorg, Coord yorg, float dxscl, float) {
    XYView::scale_view(xorg, yorg, dxscl, dxscl);
}

XYView* XYView::new_view(Coord x1, Coord y1, Coord x2, Coord y2) {
    Coord l, b, r, t;
    s2o().inverse_transform(x1, y1, l, b);
    s2o().inverse_transform(x2, y2, r, t);
    return new XYView(x1, y1, x2 - x1, y2 - y1, scene(), r - l, t - b);
}

XYView* View::new_view(Coord x1, Coord y1, Coord x2, Coord y2) {
    Coord l, b, r, t;
    s2o().inverse_transform(x1, y1, l, b);
    s2o().inverse_transform(x2, y2, r, t);
    return new View((x1 + x2) / 2, (y1 + y2) / 2, x2 - x1, scene(), r - l, t - b);
}

/*static*/ class NPInsetFrame: public MonoGlyph {
  public:
    NPInsetFrame(Glyph*);
    virtual ~NPInsetFrame();
    virtual void print(Printer*, const Allocation&) const;
};

NPInsetFrame::NPInsetFrame(Glyph* g)
    : MonoGlyph(WidgetKit::instance()->inset_frame(g)) {}
NPInsetFrame::~NPInsetFrame() {}
void NPInsetFrame::print(Printer* p, const Allocation& a) const {
    Style* s = WidgetKit::instance()->style();
    long i = 1;
    s->find_attribute("scene_print_border", i);
    // printf("NPInsetFrame %ld\n", i);
    if (i) {
        body()->print(p, a);
    } else {
        ((MonoGlyph*) body())->body()->print(p, a);
    }
}

OcViewGlyph::OcViewGlyph(XYView* v)
    : OcGlyph(new Background(
          //   WidgetKit::instance()->inset_frame(
          new NPInsetFrame(LayoutKit::instance()->variable_span(v)),
          WidgetKit::instance()->background())) {
    v_ = v;
    g_ = NULL;
    v_->ref();
    assert(v_->parent() == NULL);
    v_->parent_ = this;
};

OcViewGlyph::~OcViewGlyph() {
    v_->parent_ = NULL;
    v_->unref();
    Resource::unref(g_);
}

void OcViewGlyph::save(ostream& o) {
    Scene* s = v_->scene();
    char buf[256];
    long i = Scene::scene_list_index(s);
    if (!s->mark()) {
        s->save_phase1(o);
        sprintf(buf, "scene_vector_[%ld] = save_window_", i);
    } else {
        sprintf(buf, "save_window_ = scene_vector_[%ld]", i);
    }
    o << buf << endl;
    v_->save(o);
    if (!s->mark()) {
        s->save_phase2(o);
        s->mark(true);
    }
}

ViewWindow::ViewWindow(XYView* v, const char* name)
    : PrintableWindow(new OcViewGlyph(v)) {
    if (name) {
        type(name);
    }
    v->attach(this);
    update(v);
}

ViewWindow::~ViewWindow() {
    OcViewGlyph* g = (OcViewGlyph*) glyph();
    g->view()->detach(this);
}

void ViewWindow::update(Observable* o) {
    char s[200];
    XYView* v = (XYView*) o;
    sprintf(s,
            "%s %s x %g : %g  y %g : %g",
            type(),
            v->scene()->picker()->select_name(),
            v->left(),
            v->right(),
            v->bottom(),
            v->top());
    name(s);
}
#endif
