/*
 * GNU.FREE 2002
 *
 * Copyright (c) 1999, 2000, 2001, 2002
 * The Free Software Foundation (www.fsf.org)
 *
 * GNU.FREE Co-ordinator: Jason Kitcat <jeep@free-project.org>
 *
 * GNU site: http://www.gnu.org/software/free/
 * 
 * FREE e-democracy site: http://www.free-project.org
 *
 * 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 (COPYING); if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */
 
 // statement below kept out of good form but this code was taken from the GPLed NFC Chat system.
 
/*
 * Copyright (c) 2000 Lyrisoft Solutions, Inc.
 * Used by permission
 */
 
package Free.awt;

import java.awt.*;
import java.util.Vector;
import java.util.Enumeration;

/**
 * An alternative TextView (non-editable) that allows font colors, sytles,
 * and word-wrap.<br>
 * <br>
 * Originally from NFC Chat. Modified for use in GNU.FREE<br>
 * <br>
 * Works in JDK1.0.2<br>
 * <br>
 *
 * @version 1.0 2 April 2001
 * @author Jason Kitcat
 * @since 1.6
 */
public class TextView extends Canvas {
    public static Font DEFAULT_FONT = new Font("Dialog", Font.PLAIN, 10);
    protected Vector _runs;
    protected TextStyle _defaultStyle;

    private Image _image;
    private Graphics _graphics;
    private Dimension _bufferSize = new Dimension(0, 0);
    private int _fullHeight;
    private ScrollView _scrollView;
    protected int _yTranslation = 0;

    private Point _nextDrawPoint = new Point(0, 0);
    private Dimension _scratchDimension = new Dimension(0, 0);

    private boolean _autoScrolling;

    /* index of the first viewable TextRun */
    protected int _firstRun = 0;

    public TextView(boolean autoScrolling) {
        _runs = new Vector();
        setFont(DEFAULT_FONT);
        _autoScrolling = autoScrolling;
        reshape(0, 0, 1024, 768);
        _defaultStyle = new TextStyle(getFont(), Color.black);
    }

    public TextView() {
        this(false);
    }

    public TextStyle getDefaultStyle() {
        return _defaultStyle;
    }

    public void setScrollView(ScrollView sv) {
        _scrollView = sv;
    }

    public void setFont(String name) {
        Font oldFont = getFont();
        Font newFont = new Font(name, oldFont.getStyle(), oldFont.getSize());
        setFont(newFont);
    }

    public void setFontSize(int size) {
        Font oldFont = getFont();
        Font newFont = new Font(oldFont.getName(), oldFont.getStyle(), size);
        setFont(newFont);
    }

    public void setFont(Font f) {
        super.setFont(f);
        _defaultStyle = new TextStyle(f, getForeground());
    }

    public void append(String s, TextStyle style) {
        if (s.length() == 0) {
            return;
        }
        TextRun run = new TextRun(s, style);
        append(run);
    }

    public synchronized void append(TextRun run) {
        _runs.addElement(run);
        prepare(run);
        if (_scrollView != null) {
            _scrollView.boundsChanged();
            if (_autoScrolling) {
                _scrollView.scrollToBottom();
            }
        }
        repaint();
    }

    public void append(String s) {
        append(s, _defaultStyle);
    }

    public void setYTranslation(int y) {
        _yTranslation = y;
    }

    public void update(Graphics g) {
        paint(g);
    }

    public void paint(Graphics g) {
        renderViewable(g);
    }

    public void show() {
        if (_autoScrolling) {
            _scrollView.scrollToBottom();
        }
    }

    public void reshape(int x, int y, int w, int h) {
        boolean reRender = size().width != w;
        super.reshape(x, y, w, h);
        if (!createBuffer()) {
            return;
        }
        if (reRender) {
            prepareAll();
        }
        if (_scrollView != null) {
            _scrollView.boundsChanged();
            _scrollView.scrollToBottom();
        }
        repaint();
    }

    boolean createBuffer() {
        Dimension size = size();
        if (size.width <= 0 || size.height <= 0) {
            return false;
        }
        _image = createImage(size.width, size.height);
        if (_image == null) {
            return false;
        }

        // dispose old graphics if we have one
        if (_graphics != null) {
            _graphics.dispose();
        }
        _graphics = _image.getGraphics();
        return true;
    }

    public Dimension preferredSize() {
        return new Dimension(size().width, _fullHeight);
    }

    public void prepare(TextRun run) {
        int oldY = _nextDrawPoint.y;
        run.prepare(size().width, _scratchDimension, _nextDrawPoint);
        _fullHeight = oldY + _scratchDimension.height;
    }

    public synchronized void prepareAll() {
        _nextDrawPoint.x = 0;
        _nextDrawPoint.y = 0;
        int width = size().width;
        for (Enumeration e = _runs.elements(); e.hasMoreElements(); ) {
            TextRun run = (TextRun)e.nextElement();
            prepare(run);
        }
    }

    public synchronized void renderViewable(Graphics g) {
        Dimension size = size();

        if (_graphics == null) {
            if (!createBuffer()) {
                return;
            }
        }
        _graphics.setColor(getBackground());
        _graphics.fillRect(0, 0, size.width, size.height);


        // Iterate through all the runs of text.
        TextRun run = null;
        _firstRun = -1;
        int i=0;
        for (Enumeration e = _runs.elements(); e.hasMoreElements(); ) {
            run = (TextRun)e.nextElement();

            // get the bounding rectangle of the next run
            Rectangle r = run.getBoundingRect();

            // Is the TextRun inside the viewable range?
            if (r.y -_yTranslation + r.height >= 0) {
                if (_firstRun == -1) {
                    _firstRun = i;
                }
                // Is the TextRun below the screen?
                if (r.y - _yTranslation > size.height) {
                    // Yes, we're done
                    break;
                }

                // Yes, draw it.
                run.draw(_graphics, -_yTranslation);
            }
            i++;
        }
        g.drawImage(_image, 0, 0, this);
    }
    
} //EOF Class
