package tctable;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;


public class TCTable 
{
	public int id=0; //Идентификатор таблицы
	public String name=""; //Название таблицы
	public List<TCField> fields=new ArrayList<TCField>(); //Список полей

	private int nc=0; //Байтов под NULL значения
	private byte[] m_NULL=null; //NULL значения
	private InputStream m_file;

	/**
	 * Конструктор
	 * @param Строка name Название таблицы
	 * @param Целое id Идентификатор таблицы (обычно уникальный)
	 */
	public TCTable(String name, int id)
	{	this.name=name;
		this.id=id;
	}

	//Открыть таблицу по названию файла
	/*function OpenTableF(file)
	{
		if(file_exists(file))
		{
			this.OpenTableH(fopen(file,'r'));
		}
	}*/

	//Открыть таблицу из потока HANDLE
	public boolean OpenTableH(InputStream handle) throws IOException
	{
		this.m_file=handle;
		DataInputStream dis = new DataInputStream(handle);

		if(Tools.readUShort(dis)!=65500) return false; //id файла
		if(Tools.readUShort(dis)!=1) return false; //Версия файла
		this.id= Tools.readInt(dis); //ID таблицы или запроса (4 байта можно сделать 2)
		if(dis.readByte()!=0) return false; //Только плотные таблицы
		//Считываем название таблицы
		this.name = Tools.readUTF8_1(dis);

		//Считываем столбцы
		int count=dis.readUnsignedByte(); //Количество столбцов
		for(int i=0;i<count;i++)
		{
			TCField field=new TCField(Tools.readUTF8_1(dis), dis.readUnsignedByte());
			this.addField(field);
		}
		return true;
	}
	//Открыть таблицу из потока
	//OpenTable

	//Прочитать следующую запись из потока
	public boolean ReadNextRecord()
	{
		Boolean result=true;
		try
		{
			DataInputStream dis = new DataInputStream(m_file);
			//if(m_file.available()) return false; //Неработает
	
			if(dis.available()==0)
				return false;
	
			//Считываем NULL значения
			if(m_NULL==null) m_NULL = new byte[nc];
			for(int i=0;i<nc;i++)
			{
				m_NULL[i]=(byte)dis.readUnsignedByte();
			}
	
			clearRows();
			for(int i=0;i<fields.size();i++)
			{
				if(Tools.getBit(m_NULL,i))
				{
					fields.get(i).ReadValue(m_file);
				}
			}
		}catch(Exception e)
		{
			result=false;
		}
		return result;
	}

	//Добавить поле к таблице
	public void addField(TCField field)
	{	if(field!=null)
		{	fields.add(field);
			this.nc=(int) Math.ceil(fields.size()/8.0); //Байтов под NULL
			m_NULL=new byte[nc];
		}
	}

	//Получить заголовок плотной таблицы в виде двоичной строки
	public boolean getHeader(OutputStream os)
	{
		boolean result=true;
		try {
			//File ID: 2 bytes.
			os.write((65500 & 0x000000ff));
			os.write((65500 & 0x0000ff00) >> 8);
			//File version: 2 bytes.
			os.write((1 & 0x000000ff));
			os.write((1 & 0x0000ff00) >> 8);	
			//Table ID (or Request ID): 4 bytes.
			os.write((this.id & 0x000000ff));
			os.write((this.id & 0x0000ff00) >> 8);
			os.write((this.id & 0x00ff0000) >> 16);
			os.write((this.id & 0xff000000) >> 24);
			//Table type: 1 byte (0- "Dense" 1- "Loose")
			os.write(0);
			//UTF8_1 String
			byte[] ba = this.name.getBytes("UTF-8");
			os.write(ba.length);
			os.write(ba);
			//Count of fields: 1 byte.
			os.write(this.fields.size());
			//Write name and type id
			for(int i=0;i<this.fields.size();i++)
			{
				ba = this.fields.get(i).name.getBytes("UTF-8");
				os.write(ba.length);
				os.write(ba);
				os.write(this.fields.get(i).type);
			}
		} catch (IOException e) {
			result=false;
		}
		return result;
	}
	
	//Получить данные 1 записи в виде строки
	public boolean getCol(OutputStream os)
	{
		boolean result=true;
		//Запишем NULL значения побайтно (1-есть данные 0-нету данных)
		int nc=(int) Math.ceil(fields.size()/8.0); //Байтов под NULL
		byte[] fNULL=new byte[nc];
		for(int i=0;i<nc*8;i++)
		{
			if(i<this.fields.size() && this.fields.get(i).value!=null)
			{
				Tools.setBit(fNULL,i);
			}
		}
		//Write NULL fields
		try {
			os.write(fNULL);
		} catch (IOException e1) {
			result=false;
		}
		//Запишем сами данные в строку
		for(int i=0;i<fields.size();i++)
		{
			try {
				if(fields.get(i).value!=null)
					os.write(fields.get(i).value);
			} catch (IOException e) {
				result=false;
			}
		}
		return result;
	}

	//Row очистить запись
	void clearRows()
	{	for(int i=0;i<fields.size();i++)
		{
			fields.get(i).value=null;
		}
	}

	//Получить обьект столбца по имени
	public TCField getRowByName(String name)
	{	for(int i=0;i<fields.size();i++)
		{	if(fields.get(i).name.toUpperCase().equals(name.toUpperCase())) return fields.get(i);
		}
		return null;
	}

	//Получить объект столбца по номеру
	TCField getRowByNum(int num)
	{	return fields.get(num);
	}

}
