import java.sql.Time;

// Purpose.  Proxy design pattern
// 1. Create a "wrapper" for a remote, or expensive, or sensitive target
// 2. Encapsulate the complexity/overhead of the target in the wrapper
// 3. The client deals with the wrapper
// 4. The wrapper delegates to the target
// 5. To support plug-compatibility of wrapper and target, create an interface

//import java.io.*;   
//import java.net.*;

// the server will have a proxy to talk to sockets
// it also implements the same interface as the proxy the client talks to

interface ServerFace {                  // 5. To support plug-compatibility 
   String handle(String message);       //    between the wrapper and the
   double mashNum(double param);        //    target, create an interface 
   
   String printMashedNum(int num,strategyFactory fac);
}

class Local implements ServerFace {
/* intercepts calls to the server and decides whether to contact 
	the server or just manage the call itself
*/
	 strategy strat=null;
 private int strategyCount=0;
 
  ServerFace local = new Server();    // the target... this one local
  
  public String handle (String msg) {
    if (msg.equals("bot attack")){
	   return "(proxy repels bot attack, not sent to server)"; 
	 }
	 return local.handle(msg);    // wrapper delegates to the target	
  }	
  
  public double mashNum (double num) {
	      

	 return local.mashNum(num);     // wrapper delegates to the target
		  
  } 
  
  
  public String printMashedNum(int num, strategyFactory fac){
 
	  if(strategyCount%3==0)
		  {
		  strat= fac.getStrategy();
		  strategyCount=0;
		  }
	  strategyCount++;
	  
	  double result=this.mashNum( num);
	  
	  String out=strat.print((int) result);
	  
return out;
  }
}

class CNetServer implements ServerFace {  
/* this is how the server looks if you want the server
	to live over the net as a separate process
*/	int port;		
NetProxy   net;
int strategyCount=0;
strategy strat=null;
	CNetServer(int p)
	{
		
		 port=p;
		       net = new NetProxy("localhost", port, CLIENTSIDE); 
	}
	
   private final boolean CLIENTSIDE = false;						
	
	                                                  // false means client side	
																
   public String handle (String msg) {
	
	   String str;
	   net.sendMessage("handle");
		net.sendMessage(msg);
		return net.getMessage();
	   //return "server got: "+msg;
	}	
	public double mashNum (double num) {
		
		if(isPrime((int)num))
			{
				net.sendMessage("mashNum");
				net.sendMessage(Double.toString(num));
				return Double.parseDouble(net.getMessage());
			}
		else
			return -1.0;
	}

	   boolean isPrime(int n) {
		    //check if n is a multiple of 2
		    if (n%2==0) return false;
		    //if not, then just check the odds
		    for(int i=3;i*i<=n;i+=2) {
		        if(n%i==0)
		            return false;
		    }
		    return true;
		}
	   
	   public String printMashedNum(int num, strategyFactory fac){
			  
			  if(strategyCount%3==0)
				  {
				  strat= fac.getStrategy();
				  strategyCount=0;
				  }
			  strategyCount++;
			  
			  double result=this.mashNum( num);
			  
			  String out=	  strat.print((int) result);
			  
return out;
		  }
}

class PrimeProxy implements ServerFace {
	 strategy strat=null;
	int port;		
	CNetServer serv;
	
int	strategyCount =0;
		PrimeProxy(int p)
		{
			
			 port=p;
			 serv = new CNetServer(port); 
		}
													
	   public String handle (String msg) {
		
		  /* String str;
		  net.sendMessage("handle");
			net.sendMessage(msg);
			return net.getMessage();
		   //return "server got: "+msg;
		    */
		   return null;
		}	
		public double mashNum (double num) {
			
			if(isPrime((int)num))
				{
					//System.out.println(port);
					serv.net.sendMessage("mashNum");
					serv.net.sendMessage(Double.toString(num));
					return Double.parseDouble(serv.net.getMessage());
				}
			else
				return -1.0;
		}

		   boolean isPrime(int n) {
			    //check if n is a multiple of 2
			    if (n%2==0) return false;
			    //if not, then just check the odds
			    for(int i=3;i*i<=n;i+=2) {
			        if(n%i==0)
			            return false;
			    }
			    return true;
			}
	
		   
		   public String printMashedNum(int num, strategyFactory fac){
				  
				  if(strategyCount%3==0)
					  {
					  strat= fac.getStrategy();
					  strategyCount=0;
					  }
				  strategyCount++;
				  
				  double result=this.mashNum( num);
				  
				  String out=  strat.print((int) result);
				return out ;  
				  
			  }
		   
}

class FourthProxy implements ServerFace {
	 strategy strat=null;
	int port;
	int counter;
	CNetServer serv;
    int       strategyCount=0;   
		FourthProxy(int p)
		{
			counter = 0;
			 port=p;
			 serv = new CNetServer(port); 
		}
													
	   public String handle (String msg) {
		
		  /* String str;
		  net.sendMessage("handle");
			net.sendMessage(msg);
			return net.getMessage();
		   //return "server got: "+msg;
		    */
		   return null;
		}	
		public double mashNum (double num) {
			
			counter++;
			
			if(counter%4 == 0)
				{
					//System.out.println(port);
					counter = 0;
					serv.net.sendMessage("mashNum");
					serv.net.sendMessage(Double.toString(num));
					return Double.parseDouble(serv.net.getMessage());
				}
			else
				return -2.0;
		}

		   boolean isPrime(int n) {
			    //check if n is a multiple of 2
			    if (n%2==0) return false;
			    //if not, then just check the odds
			    for(int i=3;i*i<=n;i+=2) {
			        if(n%i==0)
			            return false;
			    }
			    return true;
			}
	
		   
		   public String printMashedNum(int num, strategyFactory fac){
				 
				  if(strategyCount%3==0)
					  {
					  strat= fac.getStrategy();
					  strategyCount=0;
					  }
				  strategyCount++;
				  
				  double result=this.mashNum( num);
				  
				  
				  String out=  strat.print((int) result);
				return out ;  

			  }
		   
}

class SSNetClient {
	private final boolean SERVERSIDE = true;
	int port;
	
	SSNetClient(int p)
	{ port=p;}
	
	
	public void start(ServerFace srv) {
	  NetProxy net = new NetProxy("localhost", port, SERVERSIDE);
	                                                    // true means server side
	  String method, param;
	  while (true) {
	    method = net.getMessage();
		 if (method.equals("handle")) {
		   param = net.getMessage();
			System.out.println("  (net SS) server asked to handle... "+param);
		   net.sendMessage(srv.handle(param)); 
		 } else if (method.equals("mashNum")) {
		   param = net.getMessage();
			System.out.println("  (net SS) server asked to mashNum... "+param);
			net.sendMessage(Double.toString(srv.mashNum(Double.parseDouble(param))));
		 }
	  }

	}
	  
}



/* unadorned basic function computing engine
*/
public class Server implements ServerFace {  // it also implements the same interface
            int       strategyCount=0; 
            strategy strat=null;// as the proxy the client talks to																										
   public String handle (String msg) {
	   return "(server got "+msg+") "+msg.toUpperCase();
	}	
	public double mashNum (double num) {
	   return num;
	}
	
	
	  public String printMashedNum(int num, strategyFactory fac){
		   
		  if(strategyCount%3==0)
			  {
			  strat= fac.getStrategy();
			  strategyCount=0;
			  }
		  strategyCount++;
		  
		  double result=this.mashNum( num);
		  
		  String out=  strat.print((int) result);
		return out ;  
		  

	  }
}


