/*
   D-Bus Java Implementation
   Copyright (c) 2005-2006 Matthew Johnson

   This program is free software; you can redistribute it and/or modify it
   under the terms of either the GNU Lesser General Public License Version 2 or the
   Academic Free Licence Version 2.1.

   Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus.test;

import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
import java.util.Vector;

import org.freedesktop.DBus;
import org.freedesktop.dbus.DBusConnection;
import org.freedesktop.dbus.DBusInterface;
import org.freedesktop.dbus.DBusSigHandler;
import org.freedesktop.dbus.Struct;
import org.freedesktop.dbus.UInt16;
import org.freedesktop.dbus.UInt32;
import org.freedesktop.dbus.UInt64;
import org.freedesktop.dbus.Variant;
import org.freedesktop.dbus.exceptions.DBusException;
import org.freedesktop.dbus.exceptions.DBusExecutionException;
import org.freedesktop.dbus.types.DBusMapType;

import cx.ath.matthew.debug.Debug;

public class cross_test_client implements DBus.Binding.TestClient, DBusSigHandler<DBus.Binding.TestSignals.Triggered>
{
   private DBusConnection conn;
   private static Set<String> passed = new TreeSet<String>();
   private static Map<String, List<String>> failed = new HashMap<String, List<String>>();
   private static cross_test_client ctc;
   static {
      List<String> l = new Vector<String>();
      l.add("Signal never arrived");
      failed.put("org.freedesktop.DBus.Binding.TestSignals.Triggered", l);
      l = new Vector<String>();
      l.add("Method never called");
      failed.put("org.freedesktop.DBus.Binding.TestClient.Response", l);
   }
   public cross_test_client(DBusConnection conn)
   {
      this.conn = conn;
   }
   public boolean isRemote() { return false; }
   public void handle(DBus.Binding.TestSignals.Triggered t)
   {
      failed.remove("org.freedesktop.DBus.Binding.TestSignals.Triggered");
      if (new UInt64(21389479283L).equals(t.a) && "/Test".equals(t.getPath()))
         pass("org.freedesktop.DBus.Binding.TestSignals.Triggered");
      else if (!new UInt64(21389479283L).equals(t.a))
         fail("org.freedesktop.DBus.Binding.TestSignals.Triggered", "Incorrect signal content; expected 21389479283 got "+t.a);
      else if (!"/Test".equals(t.getPath()))
         fail("org.freedesktop.DBus.Binding.TestSignals.Triggered", "Incorrect signal source object; expected /Test got "+t.getPath());
   }
   public void Response(UInt16 a, double b)
   {
      failed.remove("org.freedesktop.DBus.Binding.TestClient.Response");
      if (a.equals(new UInt16(15)) && (b == 12.5))
         pass("org.freedesktop.DBus.Binding.TestClient.Response");
      else
         fail("org.freedesktop.DBus.Binding.TestClient.Response", "Incorrect parameters; expected 15, 12.5 got "+a+", "+b);
   }
   public static void pass(String test)
   {
      passed.add(test.replaceAll("[$]", "."));
   }
   public static void fail(String test, String reason)
   {
      test = test.replaceAll("[$]", ".");
      List<String> reasons = failed.get(test);
      if (null == reasons) {
         reasons = new Vector<String>();
         failed.put(test, reasons);
      }
      reasons.add(reason);
   }
   @SuppressWarnings("unchecked")
   public static void test(Class<? extends DBusInterface> iface, Object proxy, String method, Object rv, Object... parameters)
   {
      try {
         Method[] ms = iface.getMethods();
         Method m = null;
         for (Method t: ms) {
            if (t.getName().equals(method))
               m = t;
         }
         Object o = m.invoke(proxy, parameters);

         String msg = "Incorrect return value; sent ( ";
         if (null != parameters) 
            for (Object po: parameters)
               if (null != po) 
                  msg += collapseArray(po) + ",";
         msg = msg.replaceAll(".$",");");
         msg += " expected "+collapseArray(rv)+" got "+collapseArray(o);

         if (null != rv && rv.getClass().isArray()) {
            compareArray(iface.getName()+"."+method, rv,o); 
         } else if (rv instanceof Map) {
            if (o instanceof Map) {
               Map<Object,Object> a = (Map<Object,Object>) o;
               Map<Object,Object> b = (Map<Object,Object>) rv;
               if (a.keySet().size() != b.keySet().size()) {
                  fail(iface.getName()+"."+method, msg);
               } else for (Object k: a.keySet())
                  if (a.get(k) instanceof List) {
                     if (b.get(k) instanceof List)
                        if (setCompareLists((List<Object>) a.get(k), (List<Object>) b.get(k)))
                           ;
                        else
                           fail(iface.getName()+"."+method, msg);
                     else
                           fail(iface.getName()+"."+method, msg);
                  } else if (!a.get(k).equals(b.get(k))) {
                     fail(iface.getName()+"."+method, msg);
                     return;
                  }
               pass(iface.getName()+"."+method);
            } else
               fail(iface.getName()+"."+method, msg);
         } else {
            if (o == rv || (o != null && o.equals(rv)))
               pass(iface.getName()+"."+method);
            else
               fail(iface.getName()+"."+method, msg);
         }
      } catch (DBusExecutionException DBEe) {
         DBEe.printStackTrace();
         fail(iface.getName()+"."+method, "Error occurred during execution: "+DBEe.getClass().getName()+" "+DBEe.getMessage());
      } catch (InvocationTargetException ITe) {
         ITe.printStackTrace();
         fail(iface.getName()+"."+method, "Error occurred during execution: "+ITe.getCause().getClass().getName()+" "+ITe.getCause().getMessage());
      } catch (Exception e) {
         e.printStackTrace();
         fail(iface.getName()+"."+method, "Error occurred during execution: "+e.getClass().getName()+" "+e.getMessage());
      }
   }
   @SuppressWarnings("unchecked")
   public static String collapseArray(Object array)
   {
      if (null == array) return "null";
      if (array.getClass().isArray()) {
         String s = "{ ";
         for (int i = 0; i < Array.getLength(array); i++)
            s += collapseArray(Array.get(array, i))+",";
         s = s.replaceAll(".$"," }");
         return s;
      } else if (array instanceof List) {
         String s = "{ ";
         for (Object o: (List<Object>) array)
            s += collapseArray(o)+",";
         s = s.replaceAll(".$"," }");
         return s;
      } else if (array instanceof Map) {
         String s = "{ ";
         for (Object o: ((Map<Object,Object>) array).keySet())
            s += collapseArray(o)+" => "+collapseArray(((Map<Object,Object>) array).get(o))+",";
         s = s.replaceAll(".$"," }");
         return s;
      } else return array.toString();
   }
   public static <T> boolean setCompareLists(List<T> a, List<T> b)
   {
      if (a.size() != b.size()) return false;
      for (Object v: a)
         if (!b.contains(v)) return false;
      return true;
   }
   @SuppressWarnings("unchecked")
   public static List<Variant<Object>> PrimitizeRecurse(Object a, Type t)
   {
      List<Variant<Object>> vs = new Vector<Variant<Object>>();
      if (t instanceof ParameterizedType) {
         Class<Object> c = (Class<Object>) ((ParameterizedType) t).getRawType();
         if (List.class.isAssignableFrom(c)) {
            Object os;
            if (a instanceof List)
               os = ((List<Object>) a).toArray();
            else 
               os = a;
            Type[] ts = ((ParameterizedType) t).getActualTypeArguments();
            for (int i = 0; i < Array.getLength(os); i++)
               vs.addAll(PrimitizeRecurse(Array.get(os, i), ts[0]));
         } else if (Map.class.isAssignableFrom(c)) {
            Object[] os = ((Map) a).keySet().toArray();
            Object[] ks = ((Map) a).values().toArray();
            Type[] ts = ((ParameterizedType) t).getActualTypeArguments();
            for (int i = 0; i < ks.length; i++)
               vs.addAll(PrimitizeRecurse(ks[i], ts[0]));
            for (int i = 0; i < os.length; i++)
               vs.addAll(PrimitizeRecurse(os[i], ts[1]));
         } else if (Struct.class.isAssignableFrom(c)) {
            Object[] os = ((Struct) a).getParameters();
            Type[] ts = ((ParameterizedType) t).getActualTypeArguments();
            for (int i = 0; i < os.length; i++)
               vs.addAll(PrimitizeRecurse(os[i], ts[i]));

         } else if (Variant.class.isAssignableFrom(c)) {
            vs.addAll(PrimitizeRecurse(((Variant) a).getValue(), ((Variant) a).getType()));
         }
      } else if (Variant.class.isAssignableFrom((Class) t))
         vs.addAll(PrimitizeRecurse(((Variant) a).getValue(), ((Variant) a).getType()));
      else if (t instanceof Class && ((Class) t).isArray()) {
         Type t2 = ((Class) t).getComponentType();
         for (int i = 0; i < Array.getLength(a); i++)
            vs.addAll(PrimitizeRecurse(Array.get(a, i), t2));
      }
      else vs.add(new Variant(a));

      return vs;
   }

   @SuppressWarnings("unchecked")
   public static List<Variant<Object>> Primitize(Variant<Object> a)
   {
      return PrimitizeRecurse(a.getValue(), a.getType());
   }

   @SuppressWarnings("unchecked")
   public static void primitizeTest(DBus.Binding.Tests tests, Object input)
   {
      Variant<Object> in = new Variant<Object>(input);      
      List<Variant<Object>> vs = Primitize(in);
      List<Variant<Object>> res;

      try {
      
         res = tests.Primitize(in);
         if (setCompareLists(res, vs))
            pass("org.freedesktop.DBus.Binding.Tests.Primitize");
         else
            fail("org.freedesktop.DBus.Binding.Tests.Primitize", "Wrong Return Value; expected "+collapseArray(vs)+" got "+collapseArray(res));

      } catch (Exception e) {
         if (Debug.debug) Debug.print(e);
         fail("org.freedesktop.DBus.Binding.Tests.Primitize", "Exception occurred during test: ("+e.getClass().getName()+") "+e.getMessage());
      }
   }
   public static void doTests(DBus.Peer peer, DBus.Introspectable intro, DBus.Introspectable rootintro, DBus.Binding.Tests tests, DBus.Binding.SingleTests singletests)
   {
      Random r = new Random();
      int i;
      test(DBus.Peer.class, peer, "Ping", null); 

      try { if (intro.Introspect().startsWith("<!DOCTYPE")) pass("org.freedesktop.DBus.Introspectable.Introspect");
            else fail("org.freedesktop.DBus.Introspectable.Introspect", "Didn't get valid xml data back when introspecting /Test");
      } catch (DBusExecutionException DBEe) {
         if (Debug.debug) Debug.print(DBEe);
         fail("org.freedesktop.DBus.Introspectable.Introspect", "Got exception during introspection on /Test ("+DBEe.getClass().getName()+"): "+DBEe.getMessage());
      }

      try { if (rootintro.Introspect().startsWith("<!DOCTYPE")) pass("org.freedesktop.DBus.Introspectable.Introspect");
            else fail("org.freedesktop.DBus.Introspectable.Introspect", "Didn't get valid xml data back when introspecting /");
      } catch (DBusExecutionException DBEe) { 
         if (Debug.debug) Debug.print(DBEe);
         fail("org.freedesktop.DBus.Introspectable.Introspect", "Got exception during introspection on / ("+DBEe.getClass().getName()+"): "+DBEe.getMessage());
      }

      test(DBus.Binding.Tests.class, tests, "Identity", new Variant<Integer>(new Integer(1)), new Variant<Integer>(new Integer(1))); 
      test(DBus.Binding.Tests.class, tests, "Identity", new Variant<String>("Hello"), new Variant<String>("Hello")); 

      test(DBus.Binding.Tests.class, tests, "IdentityBool", false, false); 
      test(DBus.Binding.Tests.class, tests, "IdentityBool", true, true); 
      
      test(DBus.Binding.Tests.class, tests, "Invert", false, true); 
      test(DBus.Binding.Tests.class, tests, "Invert", true, false); 
      
      test(DBus.Binding.Tests.class, tests, "IdentityByte", (byte) 0, (byte) 0); 
      test(DBus.Binding.Tests.class, tests, "IdentityByte", (byte) 1, (byte) 1); 
      test(DBus.Binding.Tests.class, tests, "IdentityByte", (byte) -1, (byte) -1); 
      test(DBus.Binding.Tests.class, tests, "IdentityByte", Byte.MAX_VALUE, Byte.MAX_VALUE); 
      test(DBus.Binding.Tests.class, tests, "IdentityByte", Byte.MIN_VALUE, Byte.MIN_VALUE); 
      i = r.nextInt();
      test(DBus.Binding.Tests.class, tests, "IdentityByte", (byte) i, (byte) i); 
      
      test(DBus.Binding.Tests.class, tests, "IdentityInt16", (short) 0, (short) 0); 
      test(DBus.Binding.Tests.class, tests, "IdentityInt16", (short) 1, (short) 1); 
      test(DBus.Binding.Tests.class, tests, "IdentityInt16", (short) -1, (short) -1); 
      test(DBus.Binding.Tests.class, tests, "IdentityInt16", Short.MAX_VALUE, Short.MAX_VALUE); 
      test(DBus.Binding.Tests.class, tests, "IdentityInt16", Short.MIN_VALUE, Short.MIN_VALUE); 
      i = r.nextInt();
      test(DBus.Binding.Tests.class, tests, "IdentityInt16", (short) i, (short) i); 
      
      test(DBus.Binding.Tests.class, tests, "IdentityInt32", 0, 0); 
      test(DBus.Binding.Tests.class, tests, "IdentityInt32", 1, 1); 
      test(DBus.Binding.Tests.class, tests, "IdentityInt32", -1, -1); 
      test(DBus.Binding.Tests.class, tests, "IdentityInt32", Integer.MAX_VALUE, Integer.MAX_VALUE); 
      test(DBus.Binding.Tests.class, tests, "IdentityInt32", Integer.MIN_VALUE, Integer.MIN_VALUE); 
      i = r.nextInt();
      test(DBus.Binding.Tests.class, tests, "IdentityInt32", i, i); 

      
      test(DBus.Binding.Tests.class, tests, "IdentityInt64", (long) 0, (long) 0); 
      test(DBus.Binding.Tests.class, tests, "IdentityInt64", (long) 1, (long) 1); 
      test(DBus.Binding.Tests.class, tests, "IdentityInt64", (long) -1, (long) -1); 
      test(DBus.Binding.Tests.class, tests, "IdentityInt64", Long.MAX_VALUE, Long.MAX_VALUE); 
      test(DBus.Binding.Tests.class, tests, "IdentityInt64", Long.MIN_VALUE, Long.MIN_VALUE); 
      i = r.nextInt();
      test(DBus.Binding.Tests.class, tests, "IdentityInt64", (long) i, (long) i); 

      test(DBus.Binding.Tests.class, tests, "IdentityUInt16", new UInt16(0), new UInt16(0)); 
      test(DBus.Binding.Tests.class, tests, "IdentityUInt16", new UInt16(1), new UInt16(1)); 
      test(DBus.Binding.Tests.class, tests, "IdentityUInt16", new UInt16(UInt16.MAX_VALUE), new UInt16(UInt16.MAX_VALUE)); 
      test(DBus.Binding.Tests.class, tests, "IdentityUInt16", new UInt16(UInt16.MIN_VALUE), new UInt16(UInt16.MIN_VALUE)); 
      i = r.nextInt();
      i = i > 0 ? i : -i;
      test(DBus.Binding.Tests.class, tests, "IdentityUInt16", new UInt16(i%UInt16.MAX_VALUE), new UInt16(i%UInt16.MAX_VALUE)); 
      
      test(DBus.Binding.Tests.class, tests, "IdentityUInt32", new UInt32(0), new UInt32(0)); 
      test(DBus.Binding.Tests.class, tests, "IdentityUInt32", new UInt32(1), new UInt32(1)); 
      test(DBus.Binding.Tests.class, tests, "IdentityUInt32", new UInt32(UInt32.MAX_VALUE), new UInt32(UInt32.MAX_VALUE)); 
      test(DBus.Binding.Tests.class, tests, "IdentityUInt32", new UInt32(UInt32.MIN_VALUE), new UInt32(UInt32.MIN_VALUE)); 
      i = r.nextInt();
      i = i > 0 ? i : -i;
      test(DBus.Binding.Tests.class, tests, "IdentityUInt32", new UInt32(i%UInt32.MAX_VALUE), new UInt32(i%UInt32.MAX_VALUE)); 
      
      test(DBus.Binding.Tests.class, tests, "IdentityUInt64", new UInt64(0), new UInt64(0)); 
      test(DBus.Binding.Tests.class, tests, "IdentityUInt64", new UInt64(1), new UInt64(1)); 
      test(DBus.Binding.Tests.class, tests, "IdentityUInt64", new UInt64(UInt64.MAX_LONG_VALUE), new UInt64(UInt64.MAX_LONG_VALUE)); 
      test(DBus.Binding.Tests.class, tests, "IdentityUInt64", new UInt64(UInt64.MAX_BIG_VALUE), new UInt64(UInt64.MAX_BIG_VALUE)); 
      test(DBus.Binding.Tests.class, tests, "IdentityUInt64", new UInt64(UInt64.MIN_VALUE), new UInt64(UInt64.MIN_VALUE)); 
      i = r.nextInt();
      i = i > 0 ? i : -i;
      test(DBus.Binding.Tests.class, tests, "IdentityUInt64", new UInt64(i%UInt64.MAX_LONG_VALUE), new UInt64(i%UInt64.MAX_LONG_VALUE)); 
      
      test(DBus.Binding.Tests.class, tests, "IdentityDouble", 0.0, 0.0); 
      test(DBus.Binding.Tests.class, tests, "IdentityDouble", 1.0, 1.0); 
      test(DBus.Binding.Tests.class, tests, "IdentityDouble", -1.0, -1.0); 
      test(DBus.Binding.Tests.class, tests, "IdentityDouble", Double.MAX_VALUE, Double.MAX_VALUE); 
      test(DBus.Binding.Tests.class, tests, "IdentityDouble", Double.MIN_VALUE, Double.MIN_VALUE); 
      i = r.nextInt();
      test(DBus.Binding.Tests.class, tests, "IdentityDouble", (double) i, (double) i); 
      
      test(DBus.Binding.Tests.class, tests, "IdentityString", "", ""); 
      test(DBus.Binding.Tests.class, tests, "IdentityString", "The Quick Brown Fox Jumped Over The Lazy Dog", "The Quick Brown Fox Jumped Over The Lazy Dog"); 
      test(DBus.Binding.Tests.class, tests, "IdentityString", "ひらがなゲーム - かなぶん", "ひらがなゲーム - かなぶん"); 
      
      testArray(DBus.Binding.Tests.class, tests, "IdentityBoolArray", Boolean.TYPE, null);
      testArray(DBus.Binding.Tests.class, tests, "IdentityByteArray", Byte.TYPE, null);
      testArray(DBus.Binding.Tests.class, tests, "IdentityInt16Array", Short.TYPE, null);
      testArray(DBus.Binding.Tests.class, tests, "IdentityInt32Array", Integer.TYPE, null);
      testArray(DBus.Binding.Tests.class, tests, "IdentityInt64Array", Long.TYPE, null);
      testArray(DBus.Binding.Tests.class, tests, "IdentityDoubleArray", Double.TYPE, null);
      
      testArray(DBus.Binding.Tests.class, tests, "IdentityArray", Variant.class, new Variant<String>("aoeu"));
      testArray(DBus.Binding.Tests.class, tests, "IdentityUInt16Array", UInt16.class, new UInt16(12));
      testArray(DBus.Binding.Tests.class, tests, "IdentityUInt32Array", UInt32.class, new UInt32(190));
      testArray(DBus.Binding.Tests.class, tests, "IdentityUInt64Array", UInt64.class, new UInt64(103948));
      testArray(DBus.Binding.Tests.class, tests, "IdentityStringArray", String.class, "asdf");
      
      int[] is = new int[0];
      test(DBus.Binding.Tests.class, tests, "Sum", 0L, is); 
      r = new Random();
      int len = (r.nextInt() % 100) + 15;
      len = (len<0 ? -len: len)+15;
      is = new int[len];
      long result = 0;
      for (i = 0; i < len; i++) {
         is[i] = r.nextInt();
         result += is[i];
      }
      test(DBus.Binding.Tests.class, tests, "Sum", result, is); 

      byte[] bs = new byte[0];
      test(DBus.Binding.SingleTests.class, singletests, "Sum", new UInt32(0), bs); 
      len = (r.nextInt() % 100);
      len = (len<0 ? -len: len)+15;
      bs = new byte[len];
      int res = 0;
      for (i = 0; i < len; i++) {
         bs[i] = (byte) r.nextInt();
         res += (bs[i] < 0 ? bs[i]+256 : bs[i]);
      }
      test(DBus.Binding.SingleTests.class, singletests, "Sum", new UInt32(res % (UInt32.MAX_VALUE+1)), bs); 

      test(DBus.Binding.Tests.class, tests, "DeStruct", new DBus.Binding.Triplet<String,UInt32,Short>("hi", new UInt32(12), new Short((short) 99)), new DBus.Binding.TestStruct("hi", new UInt32(12), new Short((short) 99))); 

      Map<String, String> in = new HashMap<String, String>();
      Map<String, List<String>> out = new HashMap<String, List<String>>();
      test(DBus.Binding.Tests.class, tests, "InvertMapping", out, in);
      
      in.put("hi", "there");
      in.put("to", "there");
      in.put("from", "here");
      in.put("in", "out");
      List<String> l = new Vector<String>();
      l.add("hi");
      l.add("to");
      out.put("there", l);
      l = new Vector<String>();
      l.add("from");
      out.put("here", l);
      l = new Vector<String>();
      l.add("in");
      out.put("out", l);
      test(DBus.Binding.Tests.class, tests, "InvertMapping", out, in);
      
      primitizeTest(tests, new Integer(1));
      primitizeTest(tests, 
            new Variant<Variant<Variant<Variant<String>>>>(
               new Variant<Variant<Variant<String>>>(
                  new Variant<Variant<String>>(
                     new Variant<String>("Hi")))));
      primitizeTest(tests, new Variant<Map<String,String>>(in, new DBusMapType(String.class,String.class)));

      test(DBus.Binding.Tests.class, tests, "Trigger", null, "/Test", new UInt64(21389479283L));

      try {
         ctc.conn.sendSignal(new DBus.Binding.TestClient.Trigger("/Test", new UInt16(15), 12.5));
      } catch (DBusException DBe) {
         if (Debug.debug) Debug.print(DBe);
         throw new DBusExecutionException(DBe.getMessage());
      }
         
      try { Thread.sleep(10000); } catch (InterruptedException Ie) {}

      test(DBus.Binding.Tests.class, tests, "Exit", null);
   }
   public static void testArray(Class<? extends DBusInterface> iface, Object proxy, String method, Class<? extends Object> arrayType, Object content)
   {
      Object array = Array.newInstance(arrayType, 0);
      test(iface, proxy, method, array, array);
      Random r = new Random();
      int l = (r.nextInt() % 100);
      array = Array.newInstance(arrayType, (l < 0 ? -l : l) + 15);
      if (null != content) 
         Arrays.fill((Object[]) array, content);
      test(iface, proxy, method, array, array);
   }
   public static void compareArray(String test, Object a, Object b) 
   {
      if (!a.getClass().equals(b.getClass())) {
         fail(test, "Incorrect return type; expected "+a.getClass()+" got "+b.getClass()); 
         return;
      }
      boolean pass = false;
      
      if (a instanceof Object[])
         pass = Arrays.equals((Object[]) a, (Object[]) b);
      else if (a instanceof byte[])
         pass = Arrays.equals((byte[]) a, (byte[]) b);
      else if (a instanceof boolean[])
         pass = Arrays.equals((boolean[]) a, (boolean[]) b);
      else if (a instanceof int[])
         pass = Arrays.equals((int[]) a, (int[]) b);
      else if (a instanceof short[])
         pass = Arrays.equals((short[]) a, (short[]) b);
      else if (a instanceof long[])
         pass = Arrays.equals((long[]) a, (long[]) b);
      else if (a instanceof double[])
         pass = Arrays.equals((double[]) a, (double[]) b);
         
      if (pass)
         pass(test);
      else {
         String s = "Incorrect return value; expected ";
         s += collapseArray(a);
         s += " got ";
         s += collapseArray(b);
         fail(test, s);
      }
   }
         
   public static void main(String[] args)
   { try {
      /* init */
      DBusConnection conn = DBusConnection.getConnection(DBusConnection.SESSION);
      ctc = new cross_test_client(conn);
      conn.exportObject("/Test", ctc);
      conn.addSigHandler(DBus.Binding.TestSignals.Triggered.class, ctc);
      DBus.Binding.Tests tests = conn.getRemoteObject("org.freedesktop.DBus.Binding.TestServer", "/Test", DBus.Binding.Tests.class);
      DBus.Binding.SingleTests singletests = conn.getRemoteObject("org.freedesktop.DBus.Binding.TestServer", "/Test", DBus.Binding.SingleTests.class);
      DBus.Peer peer = conn.getRemoteObject("org.freedesktop.DBus.Binding.TestServer", "/Test", DBus.Peer.class);
      DBus.Introspectable intro = conn.getRemoteObject("org.freedesktop.DBus.Binding.TestServer", "/Test", DBus.Introspectable.class);

      DBus.Introspectable rootintro = conn.getRemoteObject("org.freedesktop.DBus.Binding.TestServer", "/", DBus.Introspectable.class);

      doTests(peer, intro, rootintro, tests, singletests);

      /* report results */
      for (String s: passed)
         System.out.println(s+" pass");
      int i = 1;
      for (String s: failed.keySet()) 
         for (String r: failed.get(s)) {
            System.out.println(s+" fail "+i);
            System.out.println("report "+i+": "+r);
            i++;
         }
      
      conn.disconnect();
   } catch (DBusException DBe) {
      DBe.printStackTrace();
      System.exit(1);
   }}
}
