// Purpose.  Bridge design pattern
// 1. Create an implementation/body base class
// 2. Derive the separate implementations from the common abstraction
// 3. Create an interface/wrapper class that "hasa" and delegates to the impl
// 4. Embellish the interface class with derived classes if desired

class Stack {                  // 3. Create an interface/wrapper class that
   protected StackImp imp;     //    "hasa" implementation object and delegates
   public Stack( String s ) {  //    all requsts to it
      if (s.equals("java")) imp = new StackJava();
      else                  imp = new StackMine(); }
   public Stack()                { this( "java" ); }
   public void    push( int in ) { imp.push( new Integer(in) ); }
   public int     pop()          { return ((Integer)imp.pop()).intValue(); }
   public boolean isEmpty()      { return imp.empty(); }
}

class StackHanoi extends Stack {   // 4. Embellish the interface class with
   private int totalRejected = 0;  //     derived classes if desired
   public StackHanoi()           { super( "java" ); }
   public StackHanoi( String s ) { super( s ); }
   public int reportRejected()   { return totalRejected; }
   public void push( int in ) {
      if ( ! imp.empty()  &&  in > ((Integer)imp.peek()).intValue())
         totalRejected++;
      else imp.push( new Integer(in) );
}  }

interface StackImp {           // 1. Create an implementation/body base class
   Object  push( Object o );   Object  peek();
   boolean empty();            Object  pop(); }

class StackJava extends java.util.Stack implements StackImp { }

class StackMine implements StackImp {        // 2. Derive the separate impl's
   private Object[] items = new Object[20];  //    from the common abstraction
   private int      total = -1;
   public Object push( Object o ) { return items[++total] = o; }
   public Object peek()           { return items[total]; } 
   public Object pop()            { return items[total--]; }
   public boolean empty()         { return total == -1; }
}

class BridgeDemo {
   public static void main( String[] args ) {
      Stack[] stacks = { new Stack("java"), new Stack("mine"), 
         new StackHanoi("java"), new StackHanoi("mine") };
      for (int i=0, num; i < 20; i++) {
         num = (int) (Math.random() * 1000) % 40;
         for (int j=0; j < stacks.length; j++) stacks[j].push( num );
      }
      for (int i=0, num; i < stacks.length; i++) {
         while ( ! stacks[i].isEmpty())
            System.out.print( stacks[i].pop() + "  " );
         System.out.println();
      }
      System.out.println( "total rejected is "
         + ((StackHanoi)stacks[3]).reportRejected() );
}  }

// 30  3  6  10  0  14  23  39  2  5  30  20  13  31  9  4  30  11  15  36
// 30  3  6  10  0  14  23  39  2  5  30  20  13  31  9  4  30  11  15  36
// 0  2  4  11  15  36
// 0  2  4  11  15  36
// total rejected is 14

