import javax.swing.*;          // This is the final package name.
// import com.sun.java.swing.*;      // This is the JDK 1.1 Swing beta package
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.text.*;
import java.io.*;


class TelemetryReader implements Runnable {

  private AcousticGui _gui;
  private BufferedReader _reader;
  private Thread _readerThread = null;
  private int _idNo;

  public TelemetryReader(AcousticGui gui, String filename, int idNo) {
    super();
    _gui = gui;
    _idNo = idNo;

    try {
      _reader = 
	new BufferedReader(
			   new InputStreamReader(
						 new FileInputStream(filename)));
    }
    catch (FileNotFoundException e) {
      System.out.println("Couldn't open telemetry file \"" + filename + "\"");
      return;
    }

    _readerThread = new Thread(this, "readerThread");
    _readerThread.start();
  }

  public void run() {

    // Create a packet buffer
    StringBuffer buf = new StringBuffer(512);

    while (_readerThread != null) {

      try {
	while (_reader.ready()) {
	  char c = (char )_reader.read();
	  if (c != '\n')
	    // Still in packet; append character to packet buf
	    buf.append(c);
	  else {
	    // Finished packet; update telemetry gui
	    if (buf.length() > 0) {
	      _gui.update(buf.toString());
	      // Re-initialize packet buf
	      buf.setLength(0);
	    }
	  }
	}
      }
      catch (Exception e) {
	// Exception handling here
      }
      // No characters available; sleep for a bit before trying again
      try {
	_readerThread.sleep(500);
      }
      catch (InterruptedException e) {
	// Exception handling here
      }
    }
  }

  // Cause the run() method to terminate
  public void stop() {
    System.out.println("TelemetryReader.stop() - idno=" + _idNo);
    _readerThread = null;
  }
};



public class MsgBoard extends JFrame {

  JPanel _mainPane;
  JPanel _tabbedPane;
  Vector _subsystems;
  static final String LOGFILE_NAME = "syslog";

  private TelemetryReader _telemetryReader;
  private String _telemetryFilename;
  private int _readerNo = 0;


  public TelemetryPage telemetryPage;
  public Component contents;
  MsgBoard _guiInstance;

  public MsgBoard(String telemetryFilename) {

    _guiInstance = this;
    _subsystems = new Vector();

    JMenuBar menuBar;
    JMenu menu;
    JMenuItem menuItem;

    // Create the menu bar
    menuBar = new JMenuBar();
    setJMenuBar(menuBar);

    menu = new JMenu("File");
    menuBar.add(menu);

    menuItem = new JMenuItem("Open telemetry");
    menuItem.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
	System.out.println("Open telemetry file");
      }
    });  // End of inner class

    menu.add(menuItem);

    menuItem = new JMenuItem("Refresh telemetry");
    menuItem.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
	System.out.println("Restart telemetry reader on file" + 
			   _telemetryFilename);

	_telemetryReader.stop();
	_telemetryReader = new TelemetryReader(_guiInstance, 
					       _telemetryFilename,
					       _readerNo++);
      }
    });  // End of inner class

    menu.add(menuItem);

    menuItem = new JMenuItem("Exit");
    menuItem.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
	System.exit(0);
      }
    });  // End of inner class

    menu.add(menuItem);

    contents = createContents();

    _telemetryFilename = telemetryFilename;
    _telemetryReader = new TelemetryReader(this, _telemetryFilename,
					   _readerNo++);
  }



  // Create GUI contents
  private Component createContents() {
    _mainPane = new JPanel();
    _mainPane.setLayout(new BoxLayout(_mainPane, BoxLayout.Y_AXIS));

    _tabbedPane = new JTabbedPane();

    _mainPane.add(_tabbedPane);

    return pane;
  }

  synchronized void update(String messageBuffer) {

    Message message = new Message(messageBuffer);
    Subsystem subsystem = null;
    String name = message.subsystem();

    // Determine if subsystem has been added to display yet.
    for (int i = 0; i < _subsystems.size(); i++) {
      Subsystem subsystem = (Subsystem )_subsystems.elementAt(i);
      if (name.equals(subsystem.name())) {
        // Found subsystem 
        break;
      }
    }
    if (subsystem == null) {
      // New subsystem
      subsystem = new Subsystem(name);
      _tabbedPane.addTab(name, subsystem.basePane());
      _subsystems.addElement(subsystem);
    }

    subsystem.update(message);
   
  }


  public static void main(String[] args) {

    try {
      UIManager.setLookAndFeel(
			       UIManager.getCrossPlatformLookAndFeelClassName());
    } catch (Exception e) { }

    // Get options from command line
    String logFilename = LOGFILE_NAME;
    boolean error = false;
    for (int i = 0; i < args.length; i++) {
      if (args[i].equals("-log") && i < args.length-1)
	  logFilename = args[++i];
      else {
	  System.out.println("Invalid or incomplete option: " + args[i]);
	  error = true;
      }
    }

    if (error) {
      System.out.println("Options: -log filename");
      System.exit(1);
    }

    //Create the top-level container and add contents to it.
    MsgBoard app = new MsgBoard(logFilename);
    Component contents;
    contents = app.contents;
    app.getContentPane().add(contents, BorderLayout.NORTH);

    //Finish setting up the frame, and show it.
    app.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
	System.exit(0);
      }
    });
    app.pack();
    app.setVisible(true);
  }
}




class Subsystem {

  JTextArea _errors;
  JTextArea _warnings;
  JTextArea _info;
  JPanel _basePane;
  String _name;

   public Subsystem(String name) {
    
    _basePane = new JPanel();
    _basePane.setLayout(new GridLayout(0, 1));
    _name = name;


    JPanel subPane = new JPanel();
    subPane.setBorder(BorderFactory.createTitledBorder("Errors"));
    _errors = new JTextArea(5, 30);
    JScrollPane scrollPane = new JScrollPane(_errors);
    subPane.add(scrollPane);
    _basePane.add(subPane);

    JPanel subPane = new JPanel();
    subPane.setBorder(BorderFactory.createTitledBorder("Warnings"));
   _warnings = new JTextArea(5, 30);
    JScrollPane scrollPane = new JScrollPane(_warnings);
    subPane.add(scrollPane);
    _basePane.add(subPane);

    JPanel subPane = new JPanel();
    subPane.setBorder(BorderFactory.createTitledBorder("Info"));
    _info = new JTextArea(5, 30);
    JScrollPane scrollPane = new JScrollPane(_info);
    subPane.add(scrollPane);
    _basePane.add(subPane);


    parent.add(pane);
  }

  public void update(Message message) {

    switch (message.type()) {

      case Message.ERROR:
      _errors.append(message.string() + "\n");
      break;

      case Message.WARNING:
      _warnings.append(message.string() + "\n");
      break;

      case Message.INFO:
      _info.append(message.string() + "\n");
      break;

    }
  }

  String name() {
    return _name;
  }

}

/*
Message contains a prefix which specifies originating subsystem and type (INFO, ERROR, WARNING)
*/
class Message {
  private String _buffer;

  public static final int INFO = 0;
  public static final int WARNING = 1;
  public static final int ERROR = 2;

  static final String _InfoString = "info";
  static final String _WarningString = "warn";
  static final String _ErrorString = "error";
  static final char _PrefixDelimiter = '%';
  static final char _TypeDelimiter = '.';

  String _subsystem;
  String _text;
  int _type;

  public Message(string buffer) throws Exception {
    _buffer = buffer;

    int startIndex;
    int endIndex;

    if ((startIndex = _buffer.indexOf(_PrefixDelimiter)) == -1) {
      throw new Exception("Start of prefix not found");
    }
    if ((endIndex = _buffer.indexOf(_PrefixDelimiter, startIndex + 1)) 
	== -1) {
      throw new Exception("End of prefix not found");
    }

    String prefix = _buffer.substring(startIndex+1, endIndex-1);
    _text = _buffer.substring(endIndex+1);

    if ((startIndex = prefix.indexOf(_TypeDelimiter)) == -1) {
      throw new Exception("Couldn't find type delimiter");
    }

    _subsystem = prefix.substring(0, startIndex-1);
    
    String mnem = prefix.substring(startIndex+1);

    if (mnem.equalTo(_InfoString))
      _type = INFO;
    else if (mmen.equalTo(_WarningString))
      _type = WARNING;
    else if (mnem.equalTo(_ErrorString))
      _type = ERROR;
    else
      throw new Exception("Unknown message type");  
  }

  public String subsystem() {
    return _subsystem;
  }

  public int type() {
    return _type;
  }

}



}
