/*
 This file is part of GNUnet.
 (C) 2011, 2012 Christian Grothoff (and other contributing authors)

 GNUnet is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published
 by the Free Software Foundation; either version 3, or (at your
 option) any later version.

 GNUnet is distributed in the hope that it will be useful, but
 WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with GNUnet; see the file COPYING.  If not, write to the
 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.
 */

package org.gnunet.statistics;

import org.gnunet.testing.TestingFixture;
import org.gnunet.testing.TestingSubsystem;
import org.gnunet.util.*;
import org.junit.Assert;
import org.junit.Test;


public class StatisticsTest extends TestingFixture {
    public interface Next {
        void next();
    }

    public void assertStatisticsGet(AssertionList assertions, Statistics stat, final String subsystem,
                                    final String name,
                                    final long expectedValue, final Next next) {
        Program.configureLogging();
        final Assertion getAssertion = assertions.create("get %s:%s -> %s", subsystem, name, expectedValue);
        stat.get(RelativeTime.FOREVER, subsystem, name, new StatisticsReceiver() {
                    @Override
                    public void onReceive(String rsubsystem, String rname, long rvalue) {
                        System.out.println(String.format("%s:%s = %s", rsubsystem, rname, rvalue));
                        if (rsubsystem.equals(subsystem) && rname.equals(name) && rvalue == expectedValue) {
                            getAssertion.assertTrue(true);
                        } else {
                            getAssertion.assertTrue(false);
                        }
                    }

                    @Override
                    public void onTimeout() {
                        Assert.fail();
                    }

                    @Override
                    public void onDone() {
                        if (next != null) {
                            next.next();
                        }
                    }
                });
    }


    @Test(timeout = 1000)
    public void test_simple() {
        Program.configureLogging("DEBUG");
        final TestingSubsystem ts = new TestingSubsystem("statistics");

        final Statistics stat = new Statistics(ts.getConfiguration());

        final Wrapper<Boolean> contReached = new Wrapper<Boolean>(false);

        stat.set("gnj-test", "test", 42, false);

        stat.get(RelativeTime.FOREVER, "gnj-test", "test",
                new StatisticsReceiver() {
                    @Override
                    public void onReceive(String subsystem, String name, long value) {
                        Assert.assertEquals("gnj-test", subsystem);
                        Assert.assertEquals("test", name);
                        Assert.assertEquals(42, value);
                    }

                    @Override
                    public void onTimeout() {

                    }

                    public void onDone() {
                        contReached.set(true);
                        stat.destroy();

                    }
                });

        Scheduler.run();

        Assert.assertTrue(contReached.get());
    }

    /**
     * Test setting, updating and getting values with two statistics handles.
     * This test is somewhat fragile, as we have a fixed time we wait for
     * the values to be set in the service.
     */
    @Test(timeout = 1000)
    public void test_statistics_get_set() {
        Program.configureLogging();
        final TestingSubsystem ts = new TestingSubsystem("statistics");

        final AssertionList assertions = new AssertionList();

        final Statistics stat1 = new Statistics(ts.getConfiguration());

        stat1.set("gnj-test", "test1", 5, false);
        stat1.set("gnj-test", "test2", 7, false);
        stat1.set("gnj-test", "test3", 0, false);
        stat1.update("gnj-test", "test3", 5, false);
        stat1.update("gnj-test", "test3", -1, false);

        Scheduler.addDelayed(RelativeTime.fromMilliseconds(200), new Scheduler.Task() {
            @Override
            public void run(Scheduler.RunContext ctx) {
                System.out.println("timeout over");
                stat1.destroy();
                final Statistics stat2 = new Statistics(ts.getConfiguration());
                assertStatisticsGet(assertions, stat2, "gnj-test", "test1", 5, new Next() {
                    @Override
                    public void next() {
                        System.out.println("got test1");
                        assertStatisticsGet(assertions, stat2, "gnj-test", "test2", 7, new Next() {
                            @Override
                            public void next() {
                                System.out.println("got test2");
                                assertStatisticsGet(assertions, stat2, "gnj-test", "test3", 4, new Next() {
                                    @Override
                                    public void next() {
                                        System.out.println("got test3");
                                        stat2.destroy();
                                    }
                                });
                            }
                        });

                    }
                });
            }
        });


        Scheduler.run();
        assertions.assertAll();
    }


    @Test(timeout = 1000)
    public void test_watch() {
        Program.configureLogging("DEBUG");
        final TestingSubsystem ts = new TestingSubsystem("statistics");

        final Statistics stat = new Statistics(ts.getConfiguration());

        stat.watch("gnj-test", "test", new StatisticsWatcher() {
            @Override
            public void onReceive(String subsystem, String name, long value) {
                System.out.println("received update!");
                stat.destroy();
            }
        });

        // the set is sent after the watch, thus it is guaranteed we
        // well get the update
        stat.set("gnj-test", "test", 42, false);

        Scheduler.run();
    }
}
