package proxy;

import java.lang.reflect.*;
import java.util.*;

/**
 * Ten program demonstruje użycie klas pośredniczących.
 * @version 1.02 2021-04-10
 * @author Cay Horstmann
 */
public class ProxyTest
{
   public static void main(String[] args)
   {
      var elements = new Object[1000];

      // Wstawienie do tablicy obiektów pośredniczących liczb całkowitych z przedziału 1 - 1000.
      for (int i = 0; i < elements.length; i++)
      {
         Integer value = i + 1;
         var handler = new TraceHandler(value);
         Object proxy = Proxy.newProxyInstance(
            ClassLoader.getSystemClassLoader(),
            new Class[] { Comparable.class } , handler);
         elements[i] = proxy;
      }

      // Tworzenie losowej liczby całkowitej.
      Integer key = (int) (Math.random() * elements.length) + 1;

      // Szukanie liczby.
      int result = Arrays.binarySearch(elements, key);

      // Drukowanie dopasowanej wartości, jeśli zostanie znaleziona.
      if (result >= 0) System.out.println(elements[result]);
   }
}

/**
 * Obiekt obsługujący wywołanie, który drukuje nazwę metody i parametry, a następnie
 * wywołuje oryginalną metodę.
 */
class TraceHandler implements InvocationHandler
{
   private Object target;

   /**
    * Tworzy obiekt TraceHandler.
    * @param t parametr niejawny wywołania metody
    */
   public TraceHandler(Object t)
   {
      target = t;
   }

   public Object invoke(Object proxy, Method m, Object[] args) throws Throwable
   {
      // Drukowanie argumentu niejawnego.
      System.out.print(target);
      // Drukowanie nazwy metody.
      System.out.print("." + m.getName() + "(");
      // Drukowanie argumentów jawnych.
      if (args != null)
      {
         for (int i = 0; i < args.length; i++)
         {
            System.out.print(args[i]);
            if (i < args.length - 1) System.out.print(", ");
         }
      }
      System.out.println(")");

      // rzeczywiste wywołanie metody
      return m.invoke(target, args);
   }
}
}