// Copyright © 2011-2016 Andy Goryachev <andy@goryachev.com>
package goryachev.crypto;
import goryachev.common.util.CKit;


/**
 * This class provides an opaque storage for a char array.
 */
public final class OpaqueChars
	extends OpaqueMemObject
{
	public OpaqueChars(char[] cs)
	{
		set(cs);
	}
	
	
	public OpaqueChars()
	{
	}
	
	
	public void set(OpaqueChars x)
	{
		char[] cs = null;
		try
		{
			if(x != null)
			{
				cs = x.getChars();
			}
			
			set(cs);
		}
		finally
		{
			Crypto.zero(cs);
		}
	}
	
	
	public void set(String s)
	{
		char[] cs = null;
		try
		{
			if(s != null)
			{
				cs = s.toCharArray();
			}
			
			set(cs);
		}
		finally
		{
			Crypto.zero(cs);
		}
	}
	
	
	public final void set(char[] cs)
	{
		byte[] b = null;
		try
		{
			int sz = cs.length;
			b = new byte[sz + sz];
			int ix = 0;
			for(int i=0; i<sz; i++)
			{
				int c = cs[i];
				b[ix++] = (byte)(c >>> 8);
				b[ix++] = (byte)c;
			}
			
			setBytes(b);
		}
		finally
		{
			Crypto.zero(b);
		}
	}
	
	
	public final char[] getChars()
	{
		byte[] b = null;
		try
		{
			b = getBytes();
			int sz = b.length/2;
			
			char[] cs = new char[sz];
			int ix = 0;
			for(int i=0; i<sz; i++)
			{
				int c = (b[ix++] & 0xff) << 8;
				c |= (b[ix++] & 0xff);
				cs[i] = (char)c;
			}
			
			return cs;
		}
		finally
		{
			Crypto.zero(b);
		}
	}
	
	
	public boolean sameAs(OpaqueChars cs)
	{
		if(cs == null)
		{
			return false;
		}
		
		byte[] me = getBytes();
		try
		{
			byte[] him = cs.getBytes();
			try
			{
				return CKit.equals(me, him);
			}
			finally
			{
				Crypto.zero(him);
			}
		}
		finally
		{
			Crypto.zero(me);
		}
	}


	public void append(String s)
	{
		if(s != null)
		{
			append(s.toCharArray());
		}
	}
	
	
	public void append(char[] add)
	{
		char[] cs = getChars();
		try
		{
			char[] rv = new char[cs.length + add.length];
			try
			{
				System.arraycopy(cs, 0, rv, 0, cs.length);
				System.arraycopy(add, 0, rv, cs.length, add.length);
				set(rv);
			}
			finally
			{
				Crypto.zero(rv);
			}
		}
		finally
		{
			Crypto.zero(cs);
		}
	}


	public void deleteLastChar()
	{
		// TODO
	}
}

@@ -2273,15 +2273,371 @@
 %0D%0A%09%09
-// TODO
+char%5B%5D cs = getChars();%0D%0A%09%09try%0D%0A%09%09%7B%0D%0A%09%09%09int len = cs.length - 1;%0D%0A%09%09%09if(len %3E= 0)%0D%0A%09%09%09%7B%0D%0A%09%09%09%09// TODO this does not handle surrogate characters%0D%0A%09%09%09%09char%5B%5D rv = new char%5Blen%5D;%0D%0A%09%09%09%09try%0D%0A%09%09%09%09%7B%0D%0A%09%09%09%09%09System.arraycopy(cs, 0, rv, 0, len);%0D%0A%09%09%09%09%09set(rv);%0D%0A%09%09%09%09%7D%0D%0A%09%09%09%09finally%0D%0A%09%09%09%09%7B%0D%0A%09%09%09%09%09Crypto.zero(rv);%0D%0A%09%09%09%09%7D%0D%0A%09%09%09%7D%0D%0A%09%09%09%0D%0A%09%09%7D%0D%0A%09%09finally%0D%0A%09%09%7B%0D%0A%09%09%09Crypto.zero(cs);%0D%0A%09%09%7D
 %0D%0A%09%7D

delete last char