/* 
-*- coding: latin-1 -*-

This file is part of RefactorErl.

RefactorErl is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

RefactorErl 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 Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with RefactorErl.  If not, see <http://plc.inf.elte.hu/erlang/>.

The Original Code is RefactorErl.

The Initial Developer of the Original Code is Eötvös Loránd University.
Portions created  by Eötvös Loránd University and ELTE-Soft Ltd.
are Copyright 2007-2025 Eötvös Loránd University, ELTE-Soft Ltd.
and Ericsson Hungary. All Rights Reserved.
*/

package com.refactorerl.ui.common;

import java.util.HashMap;
import java.util.Map;

import com.ericsson.otp.erlang.OtpErlangAtom;
import com.ericsson.otp.erlang.OtpErlangBoolean;
import com.ericsson.otp.erlang.OtpErlangList;
import com.ericsson.otp.erlang.OtpErlangObject;
import com.ericsson.otp.erlang.OtpErlangString;
import com.ericsson.otp.erlang.OtpErlangTuple;

/**
 * This class contains useful methods to make the handling of the descendants of
 * OtpErlangObject easier or less ambiguous.
 * 
 * @author Daniel Lukacs, 2014 ELTE IK
 *
 */
public class OtpErlangHelper {
	public static OtpErlangObject toOtpErlangString(String s) {
		if (s.trim().equals("")) //$NON-NLS-1$
			return new OtpErlangList();
		else
			return new OtpErlangString(s);
	}

	public static Boolean booleanValue(OtpErlangObject o) {
		if (o instanceof OtpErlangBoolean)
			return ((OtpErlangBoolean) o).booleanValue();

		if (o instanceof OtpErlangAtom)
			return equalsAtom(o, "true"); //$NON-NLS-1$

		return null;

	}

	public static <T extends OtpErlangObject> T nth(OtpErlangObject o, int n) {
		if (o instanceof OtpErlangTuple) {
			OtpErlangTuple t = ((OtpErlangTuple) o);
			if (n < 0 || n >= t.arity())
				throw new IndexOutOfBoundsException();
			return (T) (t.elementAt(n));
		} else if (o instanceof OtpErlangList) {
			OtpErlangList t = (OtpErlangList) o;
			if (n < 0 || n >= t.arity())
				throw new IndexOutOfBoundsException();
			return (T) (t.elementAt(n));
		} else {
			throw new ClassCastException(o.getClass().toString());
		}

	}

	public static OtpErlangList createList(OtpErlangObject... args) {
		return new OtpErlangList(args);
	}

	/**
	 * Creates an OtpErlangList proplist from the supplied Map. For every tuple
	 * in the proplist, the key of the tuple will be a key from the Map. The
	 * value of that tuple will be the value matching the key in the Map.
	 * Inverse function of translatePropList(OtpErlangObject otpPropList).
	 * 
	 * @param map
	 * @return
	 */
	public static OtpErlangList createPropList(Map<String, OtpErlangObject> map) {
		OtpErlangObject[] propList = new OtpErlangObject[map.size()];
		int i = 0;
		for (Map.Entry<String, OtpErlangObject> entry : map.entrySet()) {
			propList[i] = createTuple(new OtpErlangAtom(entry.getKey()),
					entry.getValue());
			++i;
		}

		return new OtpErlangList(propList);
	}

	/**
	 * Creates an OtpErlangList proplist from the supplied args pairwise. Eg.
	 * createPropList(a,b,c,d) becomes [{a,b}, {c,d}]
	 * 
	 * @param args
	 * @return
	 */
	public static OtpErlangList createPropList(OtpErlangObject... args) {

		if (args.length == 0)
			return createList();

		if (args.length % 2 != 0)
			throw new IllegalArgumentException(Messages.OtpErlangHelper_7);

		OtpErlangObject[] propList = new OtpErlangObject[args.length / 2];

		for (int i = 0; i < args.length; i = i + 2) {
			propList[i / 2] = createTuple(args[i], args[i + 1]);
		}

		return new OtpErlangList(propList);
	}

	/**
	 * Uniform toString method to replace the ambiguous toString and stringValue
	 * // methods
	 * 
	 * @param o
	 * @return A String with quotes around it
	 */
	public static String toQuotedString(OtpErlangObject o) {
		return "\"" + toUnquotedString(o) + "\""; //$NON-NLS-1$ //$NON-NLS-2$
	}

	/**
	 * Uniform toString method to replace the ambiguous toString and stringValue
	 * // methods
	 * 
	 * @param o
	 * @return A String without quotes
	 */
	public static String toUnquotedString(OtpErlangObject o) {
		if (o instanceof OtpErlangList && ((OtpErlangList) o).arity() == 0)
			return ""; //$NON-NLS-1$

		return o.toString().replaceAll("^\"|\"$", ""); //$NON-NLS-1$ //$NON-NLS-2$
	}

	public static OtpErlangTuple createTuple(OtpErlangObject... args) {
		return new OtpErlangTuple(args);
	}

	public static boolean equalsAtom(OtpErlangObject o, String s) {
		if (o instanceof OtpErlangAtom)
			return o.equals(new OtpErlangAtom(s)); // return
													// o.toString().equals(s)
		else
			return false;
	}

	public static boolean nthEqualsAtom(OtpErlangObject o, int n, String s) {
		return equalsAtom(nth(o, n), s);
	}

	public static int arity(OtpErlangObject o) {
		if (o instanceof OtpErlangTuple) {
			OtpErlangTuple t = ((OtpErlangTuple) o);
			return t.arity();
		} else if (o instanceof OtpErlangList) {
			OtpErlangList t = (OtpErlangList) o;
			return t.arity();
		} else {
			throw new ClassCastException();
		}
	}

	/**
	 * Joins the supplied string values of the elements in OtpErlangList into a
	 * String
	 * 
	 * @param tokenList
	 * @return
	 */
	public static String parseTokenList(OtpErlangList tokenList) {
		StringBuilder sb = new StringBuilder();

		for (OtpErlangObject o : tokenList.elements()) { 
			for (OtpErlangObject p : ((OtpErlangList) o).elements()) {
				if (p instanceof OtpErlangString)
					sb.append(((OtpErlangString) p).stringValue());
			}
		}

		return sb.toString();
	}

	/**
	 * Parses the supplied proplist in to a Map. For an {a,b} tuple in the
	 * proplist, the Map will map the string value of a to b. Inverse function
	 * of createPropList(Map<String, OtpErlangObject> map).
	 * 
	 * @param otpPropList
	 * @return
	 */
	public static Map<String, OtpErlangObject> translatePropList(
			OtpErlangObject otpPropList) {
		try {
			OtpErlangList otpPropList1 = (OtpErlangList) otpPropList;
			Map<String, OtpErlangObject> tsl = new HashMap<>();
			for (OtpErlangObject tuple : otpPropList1) {
				String key = toUnquotedString(nth(tuple, 0));
				tsl.put(key, nth(tuple, 1));
			}
			return tsl;
		} catch (IndexOutOfBoundsException e) {
			throw new IllegalArgumentException(
					Messages.OtpErlangHelper_0);
		}

	}

	public static boolean isOtpCollection(OtpErlangObject o) {
		return (o instanceof OtpErlangList) || (o instanceof OtpErlangTuple);
	}
}
