/*
 * Zorbage: an algebraic data hierarchy for use in numeric processing.
 *
 * Copyright (C) 2016-2020 Barry DeZonia
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
package nom.bdezonia.zorbage.type.character;


import nom.bdezonia.zorbage.algebra.*;
import nom.bdezonia.zorbage.storage.coder.IntCoder;
import nom.bdezonia.zorbage.misc.Hasher;

/**
 * 
 * @author Barry DeZonia
 *
 */
public final class FixedStringMember
	implements
		IntCoder, Allocatable<FixedStringMember>, Duplicatable<FixedStringMember>,
		Settable<FixedStringMember>, Gettable<FixedStringMember>
{
	private int maxLen;
	private String v;
	
	public FixedStringMember(int len, String s) {
		if (len < 0)
			throw new IllegalArgumentException("max string length must be >= 0");
		maxLen = len;
		setV(s);
	}

	public FixedStringMember(int len) {
		this(len, "");
	}

	public FixedStringMember() {
		this(0);
	}
	
	public FixedStringMember(String value) {
		this(value.length(), value);
	}
	
	public FixedStringMember(FixedStringMember value) {
		this(value.maxLen, value.v);
	}
	
	public String v() {
		return v;
	}
	
	public void setV(String val) {
		String st = chars(val);
		if (maxLen < st.length()) {
			v = st.substring(0, maxLen);
		}
		else {
			v = val;
		}
	}
	
	@Override
	public void set(FixedStringMember other) {
		setV(other.v());
	}
	
	@Override
	public void get(FixedStringMember other) {
		other.setV(v());
	}

	@Override
	public String toString() {
		return v;
	}

	@Override
	public int intCount() {
		return maxLen + 1;
	}

	@Override
	public void fromIntArray(int[] arr, int index) {
		maxLen = arr[index];
		StringBuilder b = new StringBuilder();
		for (int i = 0; i < maxLen; i++) {
			int ch = arr[index+1+i];
			if (ch == 0) // NUL
				break;
			b.append((char) ch);
		}
		v = b.toString();
	}

	@Override
	public void toIntArray(int[] arr, int index) {
		arr[index] = maxLen;
		int len = v.length();
		for (int i = 0; i < len && i < maxLen; i++) {
			arr[index+1+i] = v.charAt(i);
		}
		// NUL terminate if necessary
		if (len < maxLen)
			arr[index+1+len] = 0;
	}

	@Override
	public FixedStringMember allocate() {
		return new FixedStringMember(maxLen);
	}

	@Override
	public FixedStringMember duplicate() {
		return new FixedStringMember(this);
	}

	public void getV(FixedStringMember value) {
		get(value);
	}

	public void setV(FixedStringMember value) {
		set(value);
	}

	@Override
	public int hashCode() {
		int v = 1;
		v = Hasher.PRIME * v + Hasher.hashCode(this.v);
		return v;
	}
	
	@Override
	public boolean equals(Object o) {
		if (this == o)
			return true;
		if (o instanceof FixedStringMember) {
			return G.FSTRING.isEqual().call(this, (FixedStringMember) o);
		}
		return false;
	}
	
	private String chars(String value) {
		StringBuilder b = new StringBuilder();
		int len = value.length();
		for (int i = 0; i < len; i++) {
			char ch = value.charAt(i);
			if (ch == 0) // NUL
				return b.toString();
			b.append(ch);
		}
		return b.toString();
	}
}

@@ -2188,24 +2188,48 @@
 e) %7B%0A%09%09this(
+value.codePointCount(0, 
 value.length
@@ -2230,16 +2230,17 @@
 length()
+)
 , value)
@@ -2445,16 +2445,37 @@
 maxLen %3C
+ st.codePointCount(0,
  st.leng
@@ -2483,40 +2483,150 @@
 h())
+)
  %7B%0A%09%09%09
-v = st.substring(0, maxLen
+StringBuilder b = new StringBuilder();%0A%09%09%09for (int i = 0; i %3C maxLen; i++)%0A%09%09%09%09b.appendCodePoint(st.codePointAt(i));%0A%09%09%09v = b.toString(
 );%0A%09
@@ -3170,16 +3170,18 @@
 pend
-((char) 
+CodePoint(
 ch);
@@ -3302,16 +3302,36 @@
 nt len =
+ v.codePointCount(0,
  v.lengt
@@ -3325,32 +3325,33 @@
 nt(0, v.length()
+)
 ;%0A%09%09for (int i =
@@ -3407,19 +3407,24 @@
 i%5D = v.c
-har
+odePoint
 At(i);%0A%09
@@ -4235,16 +4235,40 @@
 nt len =
+ value.codePointCount(0,
  value.l
@@ -4274,16 +4274,17 @@
 length()
+)
 ;%0A%09%09for 
@@ -4314,20 +4314,19 @@
 +) %7B%0A%09%09%09
-char
+int
  ch = va
@@ -4330,19 +4330,24 @@
  value.c
-har
+odePoint
 At(i);%0A%09
@@ -4404,16 +4404,25 @@
 b.append
+CodePoint
 (ch);%0A%09%09

Make fixed strings deal with code points internally