// Purpose.  Flyweight design pattern
//
// 1. Identify shareable state (intrinsic) and non-shareable state (extrinsic)
// 2. Create a Factory that can return an existing object or a new object
// 3. The client must use the Factory instead of "new" to request objects
// 4. The client (or a third party) must compute the extrinsic state

import java.awt.*;
import java.awt.event.*;
import javax.swing.JOptionPane;

abstract class Handler {
	ServerFace srv;
    protected Handler next;
    Handler(Handler next) {
        this.next = next;
    }    
    void doNext(int c) {
        if(next != null) {
           next.handle(c);
        }
        else{
        	System.out.println("This number cannot be handled: "+c);
        }
    }
    abstract void handle(int c);
    void showMsg(CompResult compute_result){
    	JOptionPane.showMessageDialog(null, compute_result.to_string(), "Your Result", JOptionPane.INFORMATION_MESSAGE);
    }
    void close(){
    	srv.dispose();
    	if(next != null){
    		next.close();
    	}
    }
}

class PrimeHandler extends Handler {
    
    PrimeHandler(Handler next) {
        super(next);
        srv = new PrimeNetServer("127.0.0.1", 5561);
    }
    boolean isPrime(int n) {
    if (n==1)
      return false;
    if (n==2)
      return true;
  
    for(int i=2;i<n/2;i++) {
        if(n%i==0)
            return false;
    }
    return true;
   }
    void handle(int c) {
        if(isPrime(c) ){
         System.out.println("Prime");
         showMsg(srv.mash_number(c));
        }
        else{
        	System.out.println("This is not a Prime, pass to the next");
        	doNext(c);
        }
    }
}

class OddHandler extends Handler {
	
    public OddHandler(Handler next) {
        super(next);
        srv = new OddNetServerProxy("127.0.0.1", 9876,3);
    }    
    void handle(int c) {
        if(c%2==1) {
        	System.out.println("Odd");
        	showMsg(srv.mash_number(c));
        }else{
        	System.out.println("This is not a Odd number, pass to next");
        	doNext(c);
        }
    }
}

class EvenHandler extends Handler {
    EvenHandler(Handler next) {
        super(next);
        srv = new EvenServerProxy();
    }    
    void handle(int c) {
        if(c %2 == 0) {
        	System.out.println("Even");
            showMsg(srv.mash_number(c));
        }
        else{
        	System.out.println("This is not a Even number, pass to next");
        	doNext(c);
        }
    }
}

class FlyweightFactory {
   private static java.util.Hashtable ht = new java.util.Hashtable();
   private static ButtonListener bl = new ButtonListener();
   public static Button makeButton( String num ) {
      if (ht.containsValue( num ))
         return (Button) ht.get( num );        // 2. Return an existing object
      Button btn = new Button( num );          // 1. Identify intrinsic state
      btn.addActionListener( bl );
      ht.put( num, btn );
      return btn;                              // 2. Return a new object
   }
   public static void report() {
      System.out.print( "size=" + ht.size() + "   " );
      for (java.util.Enumeration e = ht.keys(); e.hasMoreElements(); )
         System.out.print( e.nextElement() + " " );
      System.out.println();
   }  
}

class Processor{
	static Handler handler;
	
	static void setup(){
		handler = new PrimeHandler(
	            new OddHandler(new EvenHandler(null
	            )
	            ));
	}
	static void close(){
			handler.close();
	}
}

class ButtonListener implements ActionListener {
	
   public void actionPerformed( ActionEvent e) {
      Button      btn  = (Button) e.getSource();
      int i = Integer.parseInt(btn.getLabel());
      System.out.println(i + " is pressed!");
      Processor.handler.handle(i);
   }  
}

class GoodFrame extends Frame {
	public GoodFrame() {
		// add close event handler
		addWindowListener( new WindowAdapter() {
			public void windowClosing( WindowEvent e ) {
				
				System.exit(0);
			}
		} );
	}
}

class FlyweightDemo {
   public static final int NUM = 15;
   public static final int RAN = 10;

   public static void main( String[] args ) {
      Frame frame = new GoodFrame( );
      frame.setLayout( new GridLayout( NUM, NUM ) );
      for (int i=0; i < NUM; i++)
         for (int j=0; j < NUM; j++)
            // 3. The client must use the Factory to request objects
            frame.add( FlyweightFactory.makeButton( 
               Integer.toString( i*NUM + j ) ) );
      frame.pack();
      frame.setVisible( true );
      FlyweightFactory.report();
      Processor.setup();
      System.out.println("All done!");
   }  
}

