package com.tagtraum.perf.gcviewer.imp;

import com.tagtraum.perf.gcviewer.DataReader;
import com.tagtraum.perf.gcviewer.GCModel;
import com.tagtraum.perf.gcviewer.GCEvent;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

/**
 * Parses -verbose:gc output from Sun JDK 1.3.1.
 *
 * Date: Jan 30, 2002
 * Time: 5:15:44 PM
 * @author <a href="mailto:hs@tagtraum.com">Hendrik Schreiber</a>
 * @version $Id: $
 */
public class DataReaderSun1_3_1 extends AbstractDataReaderSun implements DataReader {

    private int count;
    private BufferedReader in;

    public DataReaderSun1_3_1(InputStream in) {
        this.in = new BufferedReader(new InputStreamReader(in));
    }

    public GCModel read() throws IOException {
        try {
            count = 0;
            GCModel model = new GCModel();
            model.setFormat(GCModel.Format.SUN_VERBOSE_GC);
            List lineStack = new ArrayList();
            int i;
            StringBuffer line = null;
            while ((i = in.read()) != -1) {
                char c = (char) i;
                if (c == '[') {
                    if (line != null) lineStack.add(line); // push
                    line = new StringBuffer(64);
                } else if (c == ']') {
                    try {
                        model.add(parseLine(line.toString()));
                    } catch (ParseException e) {
                        System.out.println(e.getMessage());
                    }
                    if (!lineStack.isEmpty()) {
                        line = (StringBuffer) lineStack.remove(lineStack.size() - 1); // pop
                    }
                } else {
                    if (line != null) line.append(c);
                }
            }
            return model;
        } finally {
            if (in != null) try {
                in.close();
            } catch (IOException ioe) {
            }
        }
    }

    private GCEvent parseLine(String line) throws ParseException {
        GCEvent event = new GCEvent();
        try {
            event.setTimestamp((long) count);
            count++;
            StringTokenizer st = new StringTokenizer(line, " ,->()K\r\n");
            String token = st.nextToken();
            if (token.equals("Full") && st.nextToken().equals("GC")) {
                event.setType(GCEvent.Type.FULL_GC);
            } else if (token.equals("Inc") && st.nextToken().equals("GC")) {
                event.setType(GCEvent.Type.INC_GC);
            } else if (token.equals("GC")) {
                event.setType(GCEvent.Type.GC);
            } else {
                throw new ParseException("Error parsing entry: " + line);
            }
            setMemoryAndPauses(event, line);
            // debug
            //System.out.println("Parsed: " + event);
            //System.out.println("Real  : [" + line + "]");
            return event;
        } catch (RuntimeException rte) {
            throw new ParseException("Error parsing entry: " + line + ", " + rte.toString());
        }
    }

}
