/*## (c) SECURITY EXPLORATIONS    2018 poland                                #*/
/*##     http://www.security-explorations.com                                #*/

/* THIS SOFTWARE IS PROTECTED BY DOMESTIC AND INTERNATIONAL COPYRIGHT LAWS    */
/* UNAUTHORISED COPYING OF THIS SOFTWARE IN EITHER SOURCE OR BINARY FORM IS   */
/* EXPRESSLY FORBIDDEN. ANY USE, INCLUDING THE REPRODUCTION, MODIFICATION,    */
/* DISTRIBUTION, TRANSMISSION, RE-PUBLICATION, STORAGE OR DISPLAY OF ANY      */
/* PART OF THE SOFTWARE, FOR COMMERCIAL OR ANY OTHER PURPOSES REQUIRES A      */
/* VALID LICENSE FROM THE COPYRIGHT HOLDER.                                   */

/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS    */
/* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,*/
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    */
/* SECURITY EXPLORATIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF  */
/* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE     */
/* SOFTWARE.                                                                  */

import java.lang.*;
import java.net.*;
import java.io.*;

public class ClientIf {
 private int type;
 private String desc;
 private SrvConnection conn;
 
 private StreamInput in;
 private StreamOutput out;

 private boolean connected;

 private static int cnt;

 public ClientIf(int type) throws Throwable {
  conn=SrvConnection.get(type);

  if (conn!=null) {
   in=conn.input();
   out=conn.output();

   connected=true;

   cnt++;
  }
 }

 public ClientIf(int type,String desc) throws Throwable {
  this(type);

  if (desc==null) {
   desc="[UNKNOWN]";
  }

  this.type=type;
  this.desc=desc;

  if (connected) {
   send_hello_msg(type,desc);
  }
 }

 public WrappedInput in() {
  return in;
 }

 public WrappedOutput out() {
  return out;
 }

 private void send_hello_msg(int type,String msg) throws Throwable {
  write_byte(type);
  write_string(msg);

  out.flush();
 }

 public void close() throws Throwable {
  if (cnt>0) {
   cnt--;

   if (cnt==0) {
    conn.close();
   }
  }
 }

 public int read_byte() throws Throwable {
  return in.get_byte();
 }

 public int read_short() throws Throwable {
  return in.read_short();
 }

 public int read_int() throws Throwable {
  return in.read_int();
 }

 public long read_long() throws Throwable {
  long l1=(((long)in.read_int())&0xffffffffL)<<32;
  long l2=((long)in.read_int())&0xffffffffL;

  return l1|l2;
 }

 public boolean read_boolean() throws Throwable {
  return in.read_boolean();
 }

 public String read_string() throws Throwable {
  return in.read_string();
 }

 public String read_string_with_size(int max_size) throws Throwable {
  return in.read_string_with_size(max_size);
 }

 public byte[] read_buf() throws Throwable {
  return in.read_buf();
 }

 public byte[] read_buf_with_size(int max_size) throws Throwable {
  return in.read_buf_with_size(max_size);
 }

 public int read_buf(byte b[],int off) throws Throwable {
  return in.read_buf(b,off);
 }

 public void write_byte(int val) throws Throwable {
  out.write_byte(val);
 }

 public void write_short(int val) throws Throwable {
  out.write_short(val);
 }

 public void write_int(int val) throws Throwable {
  out.write_int(val);
 }

 public void write_long(long val) throws Throwable {
  out.write_int((int)((val>>>32)&0xffffffff));
  out.write_int((int)(val&0xffffffff));
 }

 public void write_boolean(boolean val) throws Throwable {
  out.write_boolean(val);
 }

 public void write_string(String str) throws Throwable {
  out.write_string(str);
 }

 public void write_buf(byte[] b) throws Throwable {
  out.write_buf(b);
 }

 public void write_buf(byte[] b,int size) throws Throwable {
  out.write_buf(b,size);
 }

 public void flush() throws Throwable {
  out.flush();
 }

}
