//  MeCab -- Yet Another Part-of-Speech and Morphological Analyzer
//
//  Copyright(C) 2001-2006 Taku Kudo <taku@chasen.org>
//  Copyright(C) 2004-2006 Nippon Telegraph and Telephone Corporation
using System;
using System.Collections.Generic;
using System.Text;

namespace NMeCab.Core
{
	public class Writer
	{
		private const string FloatFormat = "f6";

		private delegate void WriteAction (StringBuilder os, MeCabNode bosNode);
		private WriteAction write;

		private string outputFormatType;

		public string OutputFormatType {
			get {
				return this.outputFormatType;
			}
			set {
				this.outputFormatType = value;
				switch (value) {
				case "lattice":
					this.write = this.WriteLattice;
					break;
				case "wakati":
					this.write = this.WriteWakati;
					break;
				case "none":
					this.write = this.WriteNone;
					break;
				case "dump":
					this.write = this.WriteDump;
					break;
				case "em":
					this.write = this.WriteEM;
					break;
				default:
					throw new ArgumentOutOfRangeException (value + " is not supported Format");
				}
			}
		}

		public void Open (MeCabParam param)
		{
			this.OutputFormatType = param.OutputFormatType;
		}

		public void Write (StringBuilder os, MeCabNode bosNode)
		{
			this.write (os, bosNode);
		}

		public void WriteLattice (StringBuilder os, MeCabNode bosNode)
		{
			for (MeCabNode node = bosNode.Next; node.Next != null; node = node.Next) {
				os.Append (node.Surface);
				os.Append ("\t");
				os.Append (node.Feature);
				os.AppendLine ();
			}
			os.AppendLine ("EOS");
		}

		public void WriteWakati (StringBuilder os, MeCabNode bosNode)
		{
			MeCabNode node = bosNode.Next;
			if (node.Next != null) {
				os.Append (node.Surface);
				for (node = node.Next; node.Next != null; node = node.Next) {
					os.Append (" ");
					os.Append (node.Surface);
				}
			}
			os.AppendLine ();
		}

		public void WriteNone (StringBuilder os, MeCabNode bosNode)
		{
			// do nothing
		}

		public void WriteUser (StringBuilder os, MeCabNode bosNode)
		{
			throw new NotImplementedException ();
		}

		public void WriteEM (StringBuilder os, MeCabNode bosNode)
		{
			const float MinProb = 0.0001f;
			for (MeCabNode node = bosNode; node != null; node = node.Next) {
				if (node.Prob >= MinProb) {
					os.Append ("U\t");
					if (node.Stat == MeCabNodeStat.Bos)
						os.Append ("BOS");
					else if (node.Stat == MeCabNodeStat.Eos)
						os.Append ("EOS");
					else
						os.Append (node.Surface);
					os.Append ("\t").Append (node.Feature);
					os.Append ("\t").Append (node.Prob.ToString (FloatFormat));
					os.AppendLine ();
				}
				for (MeCabPath path = node.LPath; path != null; path = path.LNext) {
					if (path.Prob >= MinProb) {
						os.Append ("B\t").Append (path.LNode.Feature);
						os.Append ("\t").Append (node.Feature);
						os.Append ("\t").Append (path.Prob.ToString (FloatFormat));
						os.AppendLine ();
					}
				}
			}
			os.AppendLine ("EOS");
		}

		public void WriteDump (StringBuilder os, MeCabNode bosNode)
		{
			for (MeCabNode node = bosNode; node != null; node = node.Next) {
#if NeedId
                os.Append(node.Id).Append(" ");
#endif
				if (node.Stat == MeCabNodeStat.Bos)
					os.Append ("BOS");
				else if (node.Stat == MeCabNodeStat.Eos)
					os.Append ("EOS");
				else
					os.Append (node.Surface);

				os.Append (" ").Append (node.Feature);
				os.Append (" ").Append (node.BPos);
				os.Append (" ").Append (node.EPos);
				os.Append (" ").Append (node.RCAttr);
				os.Append (" ").Append (node.LCAttr);
				os.Append (" ").Append (node.PosId);
				os.Append (" ").Append (node.CharType);
				os.Append (" ").Append ((int)node.Stat);
				os.Append (" ").Append (node.IsBest ? "1" : "0");
				os.Append (" ").Append (node.Alpha.ToString (FloatFormat));
				os.Append (" ").Append (node.Beta.ToString (FloatFormat));
				os.Append (" ").Append (node.Prob.ToString (FloatFormat));
				os.Append (" ").Append (node.Cost);

				for (MeCabPath path = node.LPath; path != null; path = path.LNext) {
#if NeedId
                    os.Append(" ").Append(path.LNode.Id);
#endif
					os.Append (" ");
					os.Append (":").Append (path.Cost);
					os.Append (":").Append (path.Prob.ToString (FloatFormat));
				}

				os.AppendLine ();
			}
		}

		private char GetEscapedChar (char p)
		{
			switch (p) {
			case '0':
				return '\0';
			case 'a':
				return '\a';
			case 'b':
				return '\b';
			case 't':
				return '\t';
			case 'n':
				return '\n';
			case 'v':
				return '\v';
			case 'f':
				return '\f';
			case 'r':
				return '\r';
			case 's':
				return ' ';
			case '\\':
				return '\\';
			default:
				return '\0'; //never be here
			}
		}
	}
}
