/*******************************************************************************
 * Copyright (c) 2013 Steffen Pingel and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Steffen Pingel - initial API and implementation
 *******************************************************************************/

package org.eclipse.mylyn.internal.trac.core.client;

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

import org.eclipse.mylyn.internal.trac.core.model.TracTicket;
import org.eclipse.mylyn.internal.trac.core.model.TracTicket.Key;
import org.eclipse.mylyn.internal.trac.core.util.TracUtil;

public class WebSearchResultParser {

	private final List<TracTicket> tickets = new ArrayList<TracTicket>();

	public void parse(BufferedReader reader) throws IOException, TracException {
		Key[] fields = parseHeader(reader);
		parseTickets(reader, fields);
	}

	public void parseTickets(BufferedReader reader, Key[] fields) throws IOException, InvalidTicketException {
		// create a ticket for each following line of output
		String line;
		while ((line = reader.readLine()) != null) {
			TracTicket ticket = new TracTicket();
			tickets.add(ticket);

			// include delimiters to detect empty values
			StringTokenizer t = new StringTokenizer(line, "\t", true); //$NON-NLS-1$
			for (int i = 0; i < fields.length && t.hasMoreTokens(); i++) {
				String nextToken = t.nextToken();
				if (nextToken.equals("\t")) { //$NON-NLS-1$
					// process empty value
					nextToken = ""; //$NON-NLS-1$
				} else if (t.hasMoreTokens()) {
					// skip delimiter
					t.nextToken();
				}
				Key key = fields[i];
				if (key != null) {
					assignTicketValue(ticket, key, nextToken);
				}
			}
		}
	}

	public void assignTicketValue(TracTicket ticket, Key key, String value) throws InvalidTicketException {
		try {
			if (key == Key.ID) {
				ticket.setId(Integer.parseInt(value));
			} else if (key == Key.TIME) {
				ticket.setCreated(TracUtil.parseDate(Integer.parseInt(value)));
			} else if (key == Key.CHANGE_TIME) {
				ticket.setLastChanged(TracUtil.parseDate(Integer.parseInt(value)));
			} else {
				ticket.putBuiltinValue(key, parseTicketValue(value));
			}
		} catch (NumberFormatException e) {
			// ignore to avoid spamming log
//						StatusHandler.log(new Status(IStatus.WARNING, TracCorePlugin.ID_PLUGIN, NLS.bind(
//								"Error parsing response: ''{0}''", line), e)); //$NON-NLS-1$ 
		}
	}

	private Key[] parseHeader(BufferedReader reader) throws IOException, InvalidTicketException {
		// first line contains names of returned ticket fields
		String line = reader.readLine();
		if (line == null) {
			throw new InvalidTicketException();
		}
		// the utf-8 output in Trac 1.0 starts with a byte-order mark which
		// is passed to the tokenizer since it would otherwise end up in the first token
		StringTokenizer t = new StringTokenizer(line, "\ufeff\t"); //$NON-NLS-1$
		Key[] fields = new Key[t.countTokens()];
		for (int i = 0; i < fields.length; i++) {
			fields[i] = Key.fromKey(t.nextToken());
		}
		return fields;
	}

	public List<TracTicket> getTickets() {
		return tickets;
	}

	/**
	 * Trac has special encoding rules for the returned output: None is represented by "--".
	 */
	public static String parseTicketValue(String value) {
		if ("--".equals(value)) { //$NON-NLS-1$
			return null;
		}
		return value;
	}

}
