package com.someluigi.slperiph.ccportable.shared;
import java.io.DataInputStream;
import java.io.IOException;
public class Terminal {
public static byte parseColor( int color ){
byte index = 0;
while ( color > 0 ){
color >>= 1;
index++;
}
if ( index > 15 )
return 0;
return (byte) (16 - index);
}
public static Terminal readNewPayload( DataInputStream in ) throws IOException{
//Read constructor data, and full update
Terminal term = new Terminal( in.readShort(), in.readShort(), in.readBoolean() );
term.readUpdatePayload(in);
return term;
}
public final boolean isColorSupported;
public final int w;
public final int h;
protected boolean[] isLineDirty;
public char[][] chars;
public byte[][] charColors;
protected int cursorX = 0;
protected int cursorY = 0;
public boolean cursorBlink = false;
public byte colorText;
public byte colorBackground;
public Terminal( int wide, int tall, boolean isColor ){
this.w = wide;
this.h = tall;
this.chars = new char[tall][wide];
this.isLineDirty = new boolean[tall];
this.isColorSupported = isColor;
if ( isColor )
charColors = new byte[tall][wide];
}
public void write( String text ){
if ( cursorY < 0 || cursorY > h )
return;
cursorX += write( cursorX, cursorY, text );
}
protected int write( int x, int y, String text ){
char[] line = text.toCharArray();
int len = Math.min( w - x, line.length );
int off = x < 0 ? -x : 0;
for ( int index = off; index < len; index++ )
setChar(x + index, y, line[index] );
isLineDirty[y] = true;
return len;
}
protected void setChar( int x, int y, char chr ){
chars[y][x] = chr;
if ( isColorSupported )
charColors[y][x] = (byte) (colorText | colorBackground << 4);
}
public void setCursorPos( int x, int y ){
cursorX = x;
cursorY = y;
}
public int getCursorX(){
return cursorX;
}
public int getCursorY(){
return cursorY;
}
//TODO: Scrolling has some extreme network overhead!
public void scroll( int delta ){
char[][] newChars = new char[h][];
byte[][] newCharColors = new byte[h][];
for ( int lineID = 0; lineID < h; lineID++ ){
int newID = lineID + delta;
if ( 0 <= newID && newID < h ){
newChars[lineID] = chars[newID];
if ( isColorSupported )
newCharColors[lineID] = charColors[newID];
} else {
newChars[lineID] = new char[w];
if ( isColorSupported )
newCharColors[lineID] = new byte[w];
}
isLineDirty[lineID] = true;
}
chars = newChars;
charColors = newCharColors;
}
protected void clearLine( int lineID ){
chars[lineID] = new char[w];
if ( isColorSupported )
charColors[lineID] = new byte[w];
}
public void clearLine(){
clearLine( cursorY );
}
public void clear(){
for ( int lineID = 0; lineID < h; lineID++ )
clearLine(lineID);
}
/*
* Network
*/
public void writeNewPayload( PayloadStream out ){
//Constructor data
out.writeShort( w );
out.writeShort( h );
out.writeBoolean( isColorSupported );
//Regular data, full update
writeUpdatePayload(out, true);
}
public void readUpdatePayload( DataInputStream in ) throws IOException{
//Generic data
cursorBlink = in.readBoolean();
cursorX = in.readShort();
cursorY = in.readShort();
int lineID = 0;
//Read line offset
while( lineID < h ){
int off = in.readByte(); //Skip lines that are not changed
if ( off == -1 ) //End semaphore
break;
lineID += off;
//Read char data
for( int x = 0; x < w; x++ )
chars[lineID][x] = in.readChar();
//Read colors, if supported
if ( isColorSupported ){
for( int x = 0; x < w; x++ )
charColors[lineID][x] = in.readByte();
}
}
}
public void writeUpdatePayload( PayloadStream out ){
writeUpdatePayload(out, false);
}
protected void writeUpdatePayload( PayloadStream out, boolean isFull ){
//Generic data
out.writeBoolean( cursorBlink );
out.writeShort( cursorX );
out.writeShort( cursorY );
int delta = 0;
//Write lines, one by one
for ( int y = 0; y < h; y++ ){
//Write only dirty lines, indexing is done with some offset magic
if ( isLineDirty[y] || isFull ){
out.writeByte(delta);
delta = 1;
} else {
delta++;
continue;
}
for( int x = 0; x < w; x++ ) //Write char payload
out.writeChar( chars[y][x] );
//Write colors, if supported
if ( isColorSupported ){
for( int x = 0; x < w; x++ )
out.writeByte( charColors[y][x] );
}
}
out.write( -1 ); //End semaphore
}
}