/*
 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/* @test
 * @bug 6907760 6929532
 * @summary Tests WatchService behavior when lots of events are pending
 * @library ..
 * @run main/timeout=180 LotsOfEvents
 */

import java.nio.file.*;
import static java.nio.file.StandardWatchEventKind.*;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import java.util.concurrent.TimeUnit;

public class LotsOfEvents {

    static final Random rand = new Random();

    public static void main(String[] args) throws Exception {
        Path dir = TestUtil.createTemporaryDirectory();
        try {
            testOverflowEvent(dir);
            testModifyEventsQueuing(dir);
        } finally {
            TestUtil.removeAll(dir);
        }
    }

    /**
     * Tests that OVERFLOW events are not retreived with other events.
     */
    static void testOverflowEvent(Path dir)
        throws IOException, InterruptedException
    {
        WatchService watcher = dir.getFileSystem().newWatchService();
        try {
            dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE);

            // create a lot of files
            int n = 1024;
            Path[] files = new Path[n];
            for (int i=0; i<n; i++) {
                files[i] = dir.resolve("foo" + i).createFile();
            }

            // give time for events to accumulate (improve chance of overflow)
            Thread.sleep(1000);

            // check that we see the create events (or overflow)
            drainAndCheckOverflowEvents(watcher, ENTRY_CREATE, n);

            // delete the files
            for (int i=0; i<n; i++) {
                files[i].delete();
            }

            // give time for events to accumulate (improve chance of overflow)
            Thread.sleep(1000);

            // check that we see the delete events (or overflow)
            drainAndCheckOverflowEvents(watcher, ENTRY_DELETE, n);
        } finally {
            watcher.close();
        }
    }

    static void drainAndCheckOverflowEvents(WatchService watcher,
                                            WatchEvent.Kind<?> expectedKind,
                                            int count)
        throws IOException, InterruptedException
    {
        // wait for key to be signalled - the timeout is long to allow for
        // polling implementations
        WatchKey key = watcher.poll(15, TimeUnit.SECONDS);
        if (key != null && count == 0)
            throw new RuntimeException("Key was signalled (unexpected)");
        if (key == null && count > 0)
            throw new RuntimeException("Key not signalled (unexpected)");

        int nread = 0;
        boolean gotOverflow = false;
        while (key != null) {
            List<WatchEvent<?>> events = key.pollEvents();
            for (WatchEvent<?> event: events) {
                WatchEvent.Kind<?> kind = event.kind();
                if (kind == expectedKind) {
                    // expected event kind
                    if (++nread > count)
                        throw new RuntimeException("More events than expected!!");
                } else if (kind == OVERFLOW) {
                    // overflow event should not be retrieved with other events
                    if (events.size() > 1)
                        throw new RuntimeException("Overflow retrieved with other events");
                    gotOverflow = true;
                } else {
                    throw new RuntimeException("Unexpected event '" + kind + "'");
                }
            }
            if (!key.reset())
                throw new RuntimeException("Key is no longer valid");
            key = watcher.poll(2, TimeUnit.SECONDS);
        }

        // check that all expected events were received or there was an overflow
        if (nread < count && !gotOverflow)
            throw new RuntimeException("Insufficient events");
    }

    /**
     * Tests that check that ENTRY_MODIFY events are queued efficiently
     */
    static void testModifyEventsQueuing(Path dir)
        throws IOException, InterruptedException
    {
        // this test uses a random number of files
        final int nfiles = 5 + rand.nextInt(10);
        DirectoryEntry[] entries = new DirectoryEntry[nfiles];
        for (int i=0; i<nfiles; i++) {
            entries[i] = new DirectoryEntry(dir.resolve("foo" + i));

            // "some" of the files exist, some do not.
            entries[i].deleteIfExists();
            if (rand.nextBoolean())
                entries[i].create();
        }

        WatchService watcher = dir.getFileSystem().newWatchService();
        try {
            dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);

            // do several rounds of noise and test
            for (int round=0; round<10; round++) {

                // make some noise!!!
                for (int i=0; i<100; i++) {
                    DirectoryEntry entry = entries[rand.nextInt(nfiles)];
                    int action = rand.nextInt(10);
                    switch (action) {
                        case 0 : entry.create(); break;
                        case 1 : entry.deleteIfExists(); break;
                        default: entry.modifyIfExists();
                    }
                }

                // process events and ensure that we don't get repeated modify
                // events for the same file.
                WatchKey key = watcher.poll(15, TimeUnit.SECONDS);
                while (key != null) {
                    Set<Path> modified = new HashSet<Path>();
                    for (WatchEvent<?> event: key.pollEvents()) {
                        WatchEvent.Kind<?> kind = event.kind();
                        Path file = (kind == OVERFLOW) ? null : (Path)event.context();
                        if (kind == ENTRY_MODIFY) {
                            boolean added = modified.add(file);
                            if (!added) {
                                throw new RuntimeException(
                                    "ENTRY_MODIFY events not queued efficiently");
                            }
                        } else {
                            if (file != null) modified.remove(file);
                        }
                    }
                    if (!key.reset())
                        throw new RuntimeException("Key is no longer valid");
                    key = watcher.poll(2, TimeUnit.SECONDS);
                }
            }

        } finally {
            watcher.close();
        }
    }

    static class DirectoryEntry {
        private final Path file;
        DirectoryEntry(Path file) {
            this.file = file;
        }
        void create() throws IOException {
            if (file.notExists())
                file.createFile();

        }
        void deleteIfExists() throws IOException {
            file.deleteIfExists();
        }
        void modifyIfExists() throws IOException {
            if (file.exists()) {
                OutputStream out = file.newOutputStream(StandardOpenOption.APPEND);
                try {
                    out.write("message".getBytes());
                } finally {
                    out.close();
                }
            }
        }
    }

}
