public class ScanStatus {

    public static final ScanStatus INSTANCE = new ScanStatus();

    private int nbFilesToScan;
    private int nbOSFilesFound;
    private int nbFilesScanned;
    private String nbOSFilesFoundString = "0";
    private String displayedFilesScannedString = "0";
    private String nbFilesToScanString = "0";
    private long averageScanningTime;
    private long initTime;
    private int displayedFilesScanned;
    private long lastUpdateTime;
    private int nbQueryingFiles;

    public enum ScanState {
        INITIALIZING, QUERYING, PROCESSING, COMPLETE;
    }

    private ScanState progressState = ScanState.INITIALIZING;

    private ScanStatus() {}

    public synchronized void addFilesScanned(int count) {
        setNbFilesScanned(this.nbFilesScanned + count);
        removeNbQueryingFiles(count);
    }

    public synchronized void addOSFiles(int count) {
        setNbOSFilesFound(this.nbOSFilesFound + count);
    }

    public synchronized int getNbFilesToScan() {
        return this.nbFilesToScan;
    }

    public synchronized void setNbFilesToScan(int nbFilesToScan) {
        this.nbFilesToScan = nbFilesToScan;
        setNbFilesToScanString(NumberFormat.getInstance().format(this.nbFilesToScan));
    }

    public synchronized int getNbOSFilesFound() {
        return this.nbOSFilesFound;
    }

    public synchronized void setNbOSFilesFound(int nbOSFilesFound) {
        this.nbOSFilesFound = nbOSFilesFound;
        this.nbOSFilesFoundString = NumberFormat.getInstance().format(this.nbOSFilesFound);
    }

    public synchronized int getNbFilesScanned() {
        return this.nbFilesScanned;
    }

    public synchronized void setNbFilesScanned(int nbFilesScanned) {
        this.nbFilesScanned = nbFilesScanned;
    }

    public synchronized boolean isComplete() {
        return this.progressState == ScanState.COMPLETE;
    }

    public synchronized ScanState getProgressState() {
        return this.progressState;
    }

    public synchronized void setProgressState(ScanState scanState) {
        this.progressState = scanState;
    }

    public synchronized void setComplete() {
        this.progressState = ScanState.COMPLETE;
    }

    public synchronized void setQuerying() {
        this.progressState = ScanState.QUERYING;
    }

    public synchronized void setProcessing() {
        this.progressState = ScanState.PROCESSING;
    }

    public String getNbOSFilesFoundString() {
        return this.nbOSFilesFoundString;
    }

    public void setNbOSFilesFoundString(String nbOSFilesFoundString) {
        this.nbOSFilesFoundString = nbOSFilesFoundString;
    }

    public synchronized long getAverageScanningTime() {
        return this.averageScanningTime;
    }

    public synchronized void setAverageScanningTime(long averageScanningTime) {
        this.averageScanningTime = averageScanningTime;
    }

    public synchronized long getInitTime() {
        return this.initTime;
    }

    public synchronized void setInitTime(long initTime) {
        this.initTime = initTime;
    }

    public void start() {
        setInitTime(new Date().getTime());
    }

    public synchronized int getDisplayedFilesScanned() {
        return this.displayedFilesScanned;
    }

    public synchronized void setDisplayedFilesScanned(int displayedFilesScanned) {
        this.displayedFilesScanned = displayedFilesScanned;
        this.displayedFilesScannedString = NumberFormat.getInstance().format(
                this.displayedFilesScanned);
    }

    public synchronized long getLastUpdateTime() {
        return this.lastUpdateTime;
    }

    public synchronized void setLastUpdateTime(long lastUpdateTime) {
        this.lastUpdateTime = lastUpdateTime;
    }

    public synchronized String getDisplayedFilesScannedString() {
        return this.displayedFilesScannedString;
    }

    public synchronized void setDisplayedFilesScannedString(String displayedFilesScannedString) {
        this.displayedFilesScannedString = displayedFilesScannedString;
    }

    public synchronized int getNbQueryingFiles() {
        return this.nbQueryingFiles;
    }

    public synchronized void setNbQueryingFiles(int nbQueryingFiles) {
        this.nbQueryingFiles = nbQueryingFiles;
    }

    public synchronized void addNbQueryingFiles(int nbQueryingFiles) {
        this.nbQueryingFiles += nbQueryingFiles;
    }

    public synchronized void removeNbQueryingFiles(int nbQueryingFiles) {
        this.nbQueryingFiles -= nbQueryingFiles;
    }

    public synchronized String getNbFilesToScanString() {
        return this.nbFilesToScanString;
    }

    public synchronized void setNbFilesToScanString(String nbFilesToScanString) {
        this.nbFilesToScanString = nbFilesToScanString;
    }

} public class ScanStatusManager {

    private final static Log logger = LogFactory.getLog(ScanStatusManager.class);

    private final EventBus eventbus;

    public ScanStatusManager(EventBus eventbus) {
        super();
        this.eventbus = eventbus;

    }

    public void bind() {

        this.eventbus.addHandler(FilesIdentifiedEvent.TYPE, new FilesIdentifiedEventHandler() {

            @Override
            public String getId() {
                return getClass().getCanonicalName() + ": " + StartScanEventHandler.class.getName();
            }

            @Override
            public void handle(TreeSet<File> fileSet) {
                ScanStatus.INSTANCE.setNbFilesToScan(fileSet.size());
                ScanStatus.INSTANCE.setQuerying();
            }
        });

        this.eventbus.addHandler(ScanCompleteEvent.TYPE, new ScanCompleteEventHandler() {

            @Override
            public String getId() {
                return getClass().getCanonicalName() + ": "
                        + ScanCompleteEventHandler.class.getName();
            }

            @Override
            public void handle(ArrayList<Integer> levels) {
                logger.info("Scan finished, processing results...");
                ScanStatus.INSTANCE.setProcessing();
            }
        });

        this.eventbus.addHandler(FilesScannedEvent.TYPE, new FilesScannedEventHandler() {

            @Override
            public String getId() {
                return getClass().getCanonicalName() + ": "
                        + FilesScannedEventHandler.class.getName();
            }

            @Override
            public void handle(int count) {
                ScanStatus.INSTANCE.addFilesScanned(count);
                long averageTime = ScanStatusManager.this.computeAverageTime();
                ScanStatus.INSTANCE.setAverageScanningTime(averageTime);
                ScanStatus.INSTANCE.setLastUpdateTime(new Date().getTime());
                logger.info("Finish scan for " + count + " files, average scanning time: "
                        + averageTime + " ms");

            }

        });

        this.eventbus.addHandler(OSFilesFoundEvent.TYPE, new OSFilesFoundEventHandler() {

            @Override
            public String getId() {
                return getClass().getCanonicalName() + ": "
                        + OSFilesFoundEventHandler.class.getName();
            }

            @Override
            public void handle(Set<String> fileSet) {
                logger.info(fileSet.size() + " open source files found");
                ScanStatus.INSTANCE.addOSFiles(fileSet.size());
            }
        });

    }

    protected long computeAverageTime() {
        return (new Date().getTime() - ScanStatus.INSTANCE.getInitTime())
                / ScanStatus.INSTANCE.getNbFilesScanned();
    }
} public class SourceSquareEngine {

    public static final Log logger = LogFactory.getLog(SourceSquareEngine.class);
    private final AntepediaQuery query;

    private final EventBus eventBus;

    public SourceSquareEngine(EventBus eventBus, AntepediaQuery query) {
        this.eventBus = eventBus;
        this.query = query;
    }

    public void discover(Map<String, String> files) throws RestClientException,
            JsonGenerationException, JsonMappingException, IOException {
        ScanStatus.INSTANCE.addNbQueryingFiles(files.size());
        List<ResultEntry> results = this.query.getResults(files);
        Map<String, ResultEntry> mappedResults = null;

        if (!results.isEmpty()) {
            logger.debug(results.size() + " results");
            mappedResults = mapResults(files, results);
            this.eventBus.fireEvent(new OSFilesFoundEvent(mappedResults.keySet()));
        }
        logger.debug("done with " + files.size() + " files");
        this.eventBus.fireEvent(new FilesScannedEvent(files.size()));
    }

    private Map<String, ResultEntry> mapResults(Map<String, String> files, List<ResultEntry> results) {
        HashMap<String, ResultEntry> processed = new HashMap<String, ResultEntry>();
        for (Entry<String, String> entry : files.entrySet()) {
            for (ResultEntry resultEntry : results) {
                if (entry.getValue().equals(resultEntry.getSha1())) {
                    processed.put(entry.getKey(), resultEntry);
                }
            }
        }
        return processed;
    }

    public void DummyPass(Exception e, int size) {
        logger.error("increasing file counter following an unrecoverable error...", e);
        this.eventBus.fireEvent(new FilesScannedEvent(size));
    }
} public class SourceSquareFSWalker {

    private final static Log logger = LogFactory.getLog(SourceSquareFSWalker.class);

    private static final int MAX_FILE_PER_QUERY = 400;

    private static final int COMPUTE_WAIT_TIME = 1000;

    private final EventBus eventBus;

    private final TreeMapBuilder treemap;

    private int filePerQuery = 2;

    private final ArrayList<ProcessWorker> workers = new ArrayList<ProcessWorker>();

    /*contains number of folders per level*/
    private final ArrayList<Integer> levels;

    private final Object lock;

    private long total = 0;

    public SourceSquareFSWalker(SourceSquareEngine engine, EventBus eventBus, TreeMapBuilder treemap) {
        this.eventBus = eventBus;
        this.levels = new ArrayList<Integer>();
        this.lock = new Object();
        this.treemap = treemap;
        this.workers.add(new ProcessWorker(0, engine, this.lock));
        this.workers.add(new ProcessWorker(1, engine, this.lock));
        this.workers.add(new ProcessWorker(2, engine, this.lock));
    }

    public void bind() {
        this.eventBus.addHandler(StartScanEvent.TYPE, new StartScanEventHandler() {

            @Override
            public String getId() {
                return getClass().getCanonicalName() + ": " + StartScanEventHandler.class.getName();
            }

            @Override
            public void handle(File toScan) {
                logger.info("Counting files...");
                SourceSquareFSWalker.this.identifyFiles(toScan);
            }
        });

        this.eventBus.addHandler(FilesIdentifiedEvent.TYPE, new FilesIdentifiedEventHandler() {

            @Override
            public String getId() {
                return getClass().getCanonicalName() + ": " + StartScanEventHandler.class.getName();
            }

            @Override
            public void handle(TreeSet<File> fileSet) {
                try {
                    logger.info("Start scan for " + fileSet.size() + " files");
                    ScanStatus.INSTANCE.start();
                    SourceSquareFSWalker.this.queryFiles(fileSet);
                } catch (Exception e) {
                    logger.debug("Error handling tree identification", e);
                }

            }
        });
    }

    public synchronized void queryFiles(TreeSet<File> fileSet) throws InterruptedException {
        HashMap<String, String> toAnalyze = new HashMap<String, String>();
        Iterator<File> iterator = fileSet.iterator();
        logger.debug(fileSet.size() + " files to analyze");
        long count = 0;
        long timer = System.currentTimeMillis();
        while (iterator.hasNext()) {

            File file = iterator.next();
            logger.trace("adding analyze file to the pool: " + file.getAbsolutePath());
            try {
                String sha1 = FileAnalyzer.calculateHash("SHA-1", file);
                toAnalyze.put(file.getAbsolutePath(), sha1);
                count++;
            } catch (Exception e) {
                logger.error("skipping files " + file, e);
            }

            if (toAnalyze.size() == this.filePerQuery
                    || System.currentTimeMillis() - timer > COMPUTE_WAIT_TIME) {
                // dispatch analysis
                timer = System.currentTimeMillis();
                analyzeMap(toAnalyze);
                this.filePerQuery = Math.min(MAX_FILE_PER_QUERY, this.filePerQuery * 2);
                logger.trace("new counter: " + count);

            }
        }
        analyzeMap(toAnalyze);

        while (!allProcessDone()) {
            synchronized (this.lock) {
                this.lock.wait();
            }

        }
        this.eventBus.fireEvent(new ScanCompleteEvent(this.levels));

        logger.info("Analysis done " + count);
    }

    private synchronized void analyzeMap(HashMap<String, String> tempMap)
            throws InterruptedException {
        if (tempMap == null || tempMap.isEmpty()) {
            return;
        }
        ProcessWorker worker = null;
        while ((worker = getAvailableProcessor()) == null) {
            synchronized (this.lock) {
                this.lock.wait();
            }

        }
        worker.process(new HashMap<String, String>(tempMap));
        tempMap.clear();
    }

    public void identifyFiles(File directory) {

        logger.debug("counting files for: " + directory.getAbsolutePath());
        TreeSet<File> fileSet = new TreeSet<File>();
        try {
            TreemapNode root = reccursiveIdentifyFiles(directory, fileSet, 0);
            this.treemap.setRoot(root);
            this.eventBus.fireEvent(new FilesIdentifiedEvent(fileSet));
        } catch (OutOfMemoryError e) {
            this.eventBus
                    .fireEvent(new ErrorEvent(
                            "Out of memory: Try again with a smaller directory\nor change your JVM parameters."));
        }

    }

    private TreemapNode reccursiveIdentifyFiles(File directory, TreeSet<File> fileSet, int depth) {

        if (this.levels.size() < depth + 1) {
            this.levels.add(0);
        }

        logger.trace("Counting going down to directory : " + directory.getAbsolutePath());
        if (directory.isHidden()) {
            this.eventBus.fireEvent(new HiddenFileFoundEvent(directory));
            return null;
        }
        if (directory.isFile()) {
            fileSet.add(directory);
            return null;
        }
        if (!directory.isDirectory()) {
            return null;
        }
        // Protection if the directory forbids listing
        if (directory.listFiles() == null) {
            return null;
        }
        Set<TreemapNode> children = new HashSet<TreemapNode>();
        int nbFiles = 0;
        int nbDirs = 0;
        for (File child : directory.listFiles()) {
            if (child.isDirectory() || !child.isHidden()) {
                if (child.isDirectory()) {
                    nbDirs++;
                    TreemapNode childNode = reccursiveIdentifyFiles(child, fileSet, depth + 1);
                    if (childNode != null) {
                        children.add(childNode);
                    }
                } else if (child.isFile()) {
                    nbFiles++;
                    fileSet.add(child);
                }
            }
        }
        this.total = this.total + nbFiles;
        ScanStatus.INSTANCE.setNbFilesToScan((int) this.total);
        this.levels.set(depth, this.levels.get(depth) + nbDirs);
        return this.treemap.createTreeMapNode(directory.getAbsolutePath(), children, nbFiles);
    }

    private ProcessWorker getAvailableProcessor() {
        for (ProcessWorker worker : this.workers) {
            if (worker.isAvailable()) {
                return worker;
            }
        }
        return null;

    }

    private boolean allProcessDone() {
        for (ProcessWorker worker : this.workers) {
            if (!worker.isAvailable()) {
                return false;
            }
        }
        return true;
    }

} public class EventBus {

    private static final Log logger = LogFactory.getLog(EventBus.class);

    HashMap<ClientEventType<?>, List<? extends ClientEventHandler>> eventMap = new HashMap<ClientEventType<?>, List<? extends ClientEventHandler>>();

    @SuppressWarnings("unchecked")
    public <T extends ClientEventHandler> void addHandler(ClientEventType<T> eventType, T handler) {
        if (!this.eventMap.containsKey(eventType)) {
            this.eventMap.put(eventType, new ArrayList<T>());
        }
        ((ArrayList<T>) this.eventMap.get(eventType)).add(0, handler);
    }

    @SuppressWarnings("unchecked")
    public <T extends ClientEventHandler> void fireEvent(final ClientEvent<T> event) {
        if (!this.eventMap.containsKey(event.getHandlerType())) {
            return;
        }
        for (final ClientEventHandler handler : this.eventMap.get(event.getHandlerType())) {
            try {
                Runnable runner = new Runnable() {

                    @Override
                    public void run() { 
                        event.dispatch((T) handler);

                    }
                };

                Thread thread = new Thread(runner);
                thread.start();

                logger.trace("event dispatched to the handler " + handler.getId());
            } catch (Exception e) {
                logger.error("An event could not be dispatched to the handler " + handler.getId(), e);
            }
        }
    }
} public class StartScanEvent implements ClientEvent<StartScanEventHandler> {

    public static final ClientEventType<StartScanEventHandler> TYPE = new ClientEventType<StartScanEventHandler>();

    private final File toScan;

    public StartScanEvent(File toScan) {
        this.toScan = toScan;
    }

    @Override
    public ClientEventType<StartScanEventHandler> getHandlerType() {
        return TYPE;
    }

    @Override
    public void dispatch(StartScanEventHandler handler) {
        handler.handle(this.toScan);

    }

} public class ExitController {

    private final ExitSourceSquareView view;
    private EventBus eventBus;
    private static final Log logger = LogFactory.getLog(ExitController.class);

    public ExitController(ExitSourceSquareView view, EventBus eventBus) {
        super();
        this.view = view;
        this.setEventBus(eventBus);
    }

    public void bind() {

        this.view.getOpenButtonLabel().addMouseListener(new MouseListener() {

            @Override
            public void mouseReleased(MouseEvent arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void mousePressed(MouseEvent arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void mouseExited(MouseEvent arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void mouseEntered(MouseEvent arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void mouseClicked(MouseEvent arg0) {
                try {
                    Desktop.getDesktop().browse(new URI("http://localhost:9524/"));
                } catch (IOException e) {
                    logger.error("Error opening the browser", e);
                } catch (URISyntaxException e) {
                    logger.error("Error opening the browser", e);
                }
            }
        });

        this.eventBus.addHandler(StartScanEvent.TYPE, new StartScanEventHandler() {

            @Override
            public String getId() {
                return "Exit Controller is now Handling";
            }

            @Override
            public void handle(File toScan) {
                display();
            }
        });
        this.eventBus.addHandler(ErrorEvent.TYPE, new ErrorEventHandler() {

            @Override
            public String getId() {
                return "Handling error";
            }

            @Override
            public void handle(String error) {
                JOptionPane.showMessageDialog(ExitController.this.view, error, null,
                        JOptionPane.ERROR_MESSAGE);
                System.exit(0);
            }
        });

    }

    public void display() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    ExitController.this.view.setVisible(true);
                } catch (Exception e) {
                    logger.error("Error launching the exit UI", e);
                }
            }
        });
    }

    public EventBus getEventBus() {
        return this.eventBus;
    }

    public void setEventBus(EventBus eventBus) {
        this.eventBus = eventBus;
    }
} public class SourceSquareController {
    private final SourceSquareView view;
    private final EventBus eventBus;
    private static final Log logger = LogFactory.getLog(SourceSquareController.class);

    public SourceSquareController(SourceSquareView view, EventBus eventBus) {
        super();
        this.view = view;
        this.eventBus = eventBus;
    }

    public void bind() {

        this.view.getSelectButtonLabel().addMouseListener(new MouseListener() {

            @Override
            public void mouseReleased(MouseEvent e) {
                // TODO Auto-generated method stub

            }

            @Override
            public void mousePressed(MouseEvent e) {
                // TODO Auto-generated method stub

            }

            @Override
            public void mouseExited(MouseEvent e) {
                // TODO Auto-generated method stub

            }

            @Override
            public void mouseEntered(MouseEvent e) {
                // TODO Auto-generated method stub

            }

            @Override
            public void mouseClicked(MouseEvent e) {
                JFileChooser fileChooser = new JFileChooser();
                fileChooser.setFileHidingEnabled(false);
                fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
                int showDialog = fileChooser.showDialog(SourceSquareController.this.view, "Select directory");
                if (showDialog == JFileChooser.APPROVE_OPTION) {
                    SourceSquareController.this.view.getTextField().setText(
                            fileChooser.getSelectedFile().getAbsolutePath());
                }

            }
        });

        this.view.getScanButtonLabel().addMouseListener(new MouseListener() {

            @Override
            public void mouseReleased(MouseEvent arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void mousePressed(MouseEvent arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void mouseExited(MouseEvent arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void mouseEntered(MouseEvent arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void mouseClicked(MouseEvent arg0) {
                File toScan = new File(SourceSquareController.this.view.getTextField().getText());
                if (!toScan.exists() || toScan.list().length == 0) {
                    JOptionPane.showMessageDialog(SourceSquareController.this.view,
                            "Choose a valid and not empty directory", null, JOptionPane.ERROR_MESSAGE);
                    return;
                }
                SourceSquareController.this.view.setVisible(false);
                SourceSquareController.this.eventBus.fireEvent(new StartScanEvent(toScan));

            }
        });

    }

    public void display() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    SourceSquareController.this.view.setVisible(true);
                } catch (Exception e) {
                    logger.error("Error launching the UI", e);
                }
            }
        });
    }

} public class ExitSourceSquareView extends JFrame {

    private final static Log logger = LogFactory.getLog(ExitSourceSquareView.class);

    /**
     * 
     */
    private static final long serialVersionUID = 4204275094395452904L;
    private final JPanel contentPane;
    private JPanel mainPanel;
    private final JLabel openButtonLabel;

    /**
     * Create the frame.
     */
    public ExitSourceSquareView() {
        setIconImage(Toolkit.getDefaultToolkit().getImage(
                SourceSquareView.class.getResource("/antelink.png")));
        setTitle("SourceSquare");
        setResizable(false);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 500, 170);
        this.contentPane = new JPanel();
        this.contentPane.setBackground(Color.WHITE);
        this.contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(this.contentPane);

        this.mainPanel = new JPanel();
        this.mainPanel.setBackground(Color.WHITE);
        GroupLayout gl_contentPane = new GroupLayout(this.contentPane);
        gl_contentPane.setHorizontalGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
                .addComponent(this.mainPanel, GroupLayout.DEFAULT_SIZE, 428, Short.MAX_VALUE));
        gl_contentPane.setVerticalGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
                .addComponent(this.mainPanel, GroupLayout.DEFAULT_SIZE, 263, Short.MAX_VALUE));
        this.mainPanel.setLayout(new BoxLayout(this.mainPanel, BoxLayout.Y_AXIS));

        JPanel panel_1 = new JPanel();
        panel_1.setBackground(Color.WHITE);
        this.mainPanel.add(panel_1);
        panel_1.setLayout(new BorderLayout(0, 0));

        JPanel panel = new JPanel();
        panel.setLayout(new FlowLayout(FlowLayout.CENTER, 50, 20));
        panel.setBackground(Color.WHITE);
        panel_1.add(panel, BorderLayout.SOUTH);

        Image openButtonImage = Toolkit.getDefaultToolkit().getImage(
                SourceSquareView.class.getResource("/OpenButton.png"));
        this.openButtonLabel = new JLabel(new ImageIcon(openButtonImage));
        this.openButtonLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        panel.add(this.openButtonLabel);

        JLabel exitLabel = new JLabel(
                "<html><b>Closing this window will quit the application</b></html>");
        exitLabel.setFont(new Font("Helvetica", Font.PLAIN, 13));

        JLabel explainLabel = new JLabel(
                "<html>(You won't be able to see or publish your results anymore)</html>");
        explainLabel.setFont(new Font("Helvetica", Font.PLAIN, 13));

        JPanel textPanel = new JPanel();
        textPanel.setBackground(Color.WHITE);
        textPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 0));

        textPanel.add(exitLabel, BorderLayout.CENTER);
        textPanel.add(explainLabel, BorderLayout.CENTER);

        panel_1.add(textPanel, BorderLayout.CENTER);

        CopyrightPanel copyrightPanel = new CopyrightPanel();
        copyrightPanel.setBackground(Color.WHITE);
        this.mainPanel.add(copyrightPanel);
        this.contentPane.setLayout(gl_contentPane);

        setLocationRelativeTo(null);
    }

    @Override
    public JPanel getContentPane() {
        return this.contentPane;
    }

    public JPanel getMainPanel() {
        return this.mainPanel;
    }

    public void setMainPanel(JPanel mainPanel) {
        this.mainPanel = mainPanel;
    }

    public JLabel getOpenButtonLabel() {
        return this.openButtonLabel;
    }

} public class SourceSquareView extends JFrame {

    /**
     * 
     */
    private static final long serialVersionUID = 4204275094395452904L;
    private final JPanel contentPane;
    private final JTextField textField;
    private JPanel mainPanel;
    private final JLabel scanButtonLabel;
    private final JLabel selectButtonLabel;

    /**
     * Create the frame.
     */
    public SourceSquareView() {
        setIconImage(Toolkit.getDefaultToolkit().getImage(
                SourceSquareView.class.getResource("/antelink.png")));
        setTitle("SourceSquare");
        setResizable(false);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 443, 272);
        this.contentPane = new JPanel();
        this.contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        this.contentPane.setBackground(Color.WHITE);
        setContentPane(this.contentPane);

        this.mainPanel = new JPanel();
        this.mainPanel.setBackground(Color.WHITE);
        GroupLayout gl_contentPane = new GroupLayout(this.contentPane);
        gl_contentPane.setHorizontalGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
                .addComponent(this.mainPanel, GroupLayout.DEFAULT_SIZE, 428, Short.MAX_VALUE));
        gl_contentPane.setVerticalGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
                .addComponent(this.mainPanel, GroupLayout.DEFAULT_SIZE, 263, Short.MAX_VALUE));
        this.mainPanel.setLayout(new BoxLayout(this.mainPanel, BoxLayout.Y_AXIS));

        Image logo;
        JPanel imgPanel = new JPanel();
        imgPanel.setBackground(Color.WHITE);
        this.mainPanel.add(imgPanel, "2, 4, 3, 1, fill, fill");
        logo = Toolkit.getDefaultToolkit().getImage(
                SourceSquareView.class.getResource("/logo-SourceSquare-400-117.png"));
        JLabel picLabel = new JLabel(new ImageIcon(logo));
        imgPanel.add(picLabel, "2, 2, fill, fill");

        JPanel top = new JPanel();
        top.setBackground(Color.WHITE);
        this.mainPanel.add(top);
        top.setLayout(new FormLayout(new ColumnSpec[] { FormFactory.RELATED_GAP_COLSPEC,
                ColumnSpec.decode("default:grow"), FormFactory.RELATED_GAP_COLSPEC,
                FormFactory.DEFAULT_COLSPEC, }, new RowSpec[] { FormFactory.RELATED_GAP_ROWSPEC,
                FormFactory.DEFAULT_ROWSPEC, FormFactory.RELATED_GAP_ROWSPEC,
                RowSpec.decode("default:grow"), }));

        this.textField = new JTextField();
        this.textField.setText("Select a Directory to scan");
        top.add(this.textField, "2, 2, fill, default");
        this.textField.setColumns(10);

        Image selectButtonImage = Toolkit.getDefaultToolkit().getImage(
                SourceSquareView.class.getResource("/SelectButton.png"));
        this.selectButtonLabel = new JLabel(new ImageIcon(selectButtonImage));
        this.selectButtonLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        top.add(this.selectButtonLabel, "4, 2");

        JPanel panel = new JPanel();
        panel.setBackground(Color.WHITE);
        top.add(panel, "2, 4, 3, 1, fill, fill");

        Image scanButtonImage = Toolkit.getDefaultToolkit().getImage(
                SourceSquareView.class.getResource("/ScanButton.png"));
        this.scanButtonLabel = new JLabel(new ImageIcon(scanButtonImage));
        this.scanButtonLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        panel.add(this.scanButtonLabel);

        JPanel bottom = new CopyrightPanel();
        bottom.setBackground(Color.WHITE);
        this.mainPanel.add(bottom);
        this.contentPane.setLayout(gl_contentPane);

        setLocationRelativeTo(null);
    }

    public JTextField getTextField() {
        return this.textField;
    }

    @Override
    public JPanel getContentPane() {
        return this.contentPane;
    }

    public JPanel getMainPanel() {
        return this.mainPanel;
    }

    public void setMainPanel(JPanel mainPanel) {
        this.mainPanel = mainPanel;
    }

    public JLabel getScanButtonLabel() {
        return this.scanButtonLabel;
    }

    public JLabel getSelectButtonLabel() {
        return this.selectButtonLabel;
    }

} public class AntepediaQuery extends RestClient {

    private final static Log logger = LogFactory.getLog(AntepediaQuery.class);

    private final AntepediaLocations locations = new AntepediaLocations();

    public List<ResultEntry> getResults(Map<String, String> files) throws RestClientException,
            JsonGenerationException, JsonMappingException, IOException {

        ResponseObject response = getResponseObjects(files.values());

        if (response.hasError()) {
            response.getError().getErrorCode();
            logger.error("Error getting the results from the antepedia server : "
                    + response.getError().getErrorMessage());
            logger.error("Remote service returned error code: "
                    + response.getError().getErrorCode());
        }

        return response.getResults();
    }

    private ResponseObject getResponseObjects(Collection<String> hashes)
            throws JsonGenerationException, JsonMappingException, IOException {
        try {
            String queryUrl = this.locations.getBinaryBatchQueryUrl();
            ObjectMapper mapper = new ObjectMapper();
            String map = mapper.writeValueAsString(hashes);
            logger.info("contacting server " + queryUrl + " with " + hashes.size() + " hashs");
            ResponseObject postForObject = getTemplate(this.locations.getBaseDomain())
                    .postForObject(queryUrl, map, ResponseObject.class);
            logger.info("response received");
            return postForObject;
        } catch (UnsupportedEncodingException e) {
            logger.error("Error contacting the server", e);
            return null;
        }
    }
} public class ResultBuilder {

    private static final Log logger = LogFactory.getLog(ResultBuilder.class);

    private static final long NODE_LIMIT = 700;
    private final EventBus eventBus;
    private final TreeMapBuilder treemap;
    private final BadgesProcessor badgesProcessor;

    private ArrayList<Integer> levels;

    public ResultBuilder(EventBus eventbus, TreeMapBuilder treemap) {
        this.eventBus = eventbus;
        this.treemap = treemap;
        this.badgesProcessor = new BadgesProcessor(eventbus);
        this.badgesProcessor.bind();
    }

    public void bind() {

        this.eventBus.addHandler(ScanCompleteEvent.TYPE, new ScanCompleteEventHandler() {

            @Override
            public String getId() {
                return getClass().getCanonicalName() + ": " + ScanCompleteEventHandler.class.getName();
            }

            @Override
            public void handle(ArrayList<Integer> levels) {
                logger.info("Process results");
                ResultBuilder.this.levels = levels;
                ResultBuilder.this.processResults();
            }
        });
    }

    private void analyzeTreeMapLevels(SourceSquareResults results) {
        long cumulated = 0;
        int nodeLevel = 0;
        for (int i = 0; i < this.levels.size(); i++) {
            cumulated = cumulated + this.levels.get(i);
            if (cumulated > NODE_LIMIT) {
                nodeLevel = i;
                break;
            } else {
                nodeLevel = i + 1;
            }
        }
        results.setNodeLevel(nodeLevel);
    }

    protected void processResults() {
        this.treemap.processFinalTreeMap(this.treemap.getRootNode());
        SourceSquareResults results = new SourceSquareResults();
        analyzeTreeMapLevels(results);
        results.setRootNode(this.treemap.getRootNode());
        results.setBadges(this.badgesProcessor.process());
        this.eventBus.fireEvent(new SourceSquareResultsReadyEvent(results));
    }
} public class TreeMapBuilder {

    private final EventBus eventBus;
    private TreemapNode rootNode;
    private final Hashtable<String, TreemapNode> treeMap;

    private long countId = 0;

    public TreeMapBuilder(EventBus eventBus) {
        this.eventBus = eventBus;
        this.treeMap = new Hashtable<String, TreemapNode>();
    }

    public void bind() {

        this.eventBus.addHandler(OSFilesFoundEvent.TYPE, new OSFilesFoundEventHandler() {

            @Override
            public String getId() {
                return getClass().getCanonicalName() + ": " + OSFilesFoundEventHandler.class.getName();
            }

            @Override
            public void handle(Set<String> fileSet) {
                TreeMapBuilder.this.processOSFiles(fileSet);

            }
        });
    }

    protected void processOSFiles(Set<String> fileSet) {
        for (String path : fileSet) {
            getNodeForFile(path).incrementOSFile();
        }

    }

    private TreemapNode getNodeForFile(String path) {
        TreemapNode node = getNode(path.substring(0, path.lastIndexOf(File.separator)));
        if (node.getChildren().size() == 0) {
            return node;
        }
        return getNode(path.substring(0, path.lastIndexOf(File.separator)) + "_");
    }

    protected void processFinalTreeMap(TreemapNode node) {

        int cumulatedFiles = node.getNbFiles();
        int cumulatedOSFiles = node.getNbOSFiles();
        Iterator<TreemapNode> it = node.getChildren().iterator();
        while (it.hasNext()) {
            TreemapNode child = it.next();
            processFinalTreeMap(child);
            if (child.getCumulatedFiles() == 0) {
                it.remove();
                this.treeMap.remove(child.getName());
            }
            cumulatedFiles += child.getCumulatedFiles();
            cumulatedOSFiles += child.getCumulatedOSFiles();
        }
        node.setCumulatedFiles(cumulatedFiles);
        node.setCumulatedOSFiles(cumulatedOSFiles);
        node.processColor();
        node.processArea();

    }

    public TreemapNode createTreeMapNode(String path, Set<TreemapNode> children, int nbFiles) {
        TreemapNode node = getNode(path);
        if (children != null && !children.isEmpty()) {
            node.setChildren(children);
            TreemapNode fileSetNode = getNode(path + "_");
            fileSetNode.getData().setFileSet(true);
            fileSetNode.setNbFiles(nbFiles);
            node.addChild(fileSetNode);
        } else {
            node.setNbFiles(nbFiles);

        }
        return node;
    }

    private TreemapNode getNode(String path) {
        if (this.treeMap.keySet().contains(path)) {
            return this.treeMap.get(path);
        }

        TreemapNode node = new TreemapNode(path);
        node.setId(String.valueOf(getIdCount()));
        incrementIdCount();
        this.treeMap.put(path, node);
        return node;
    }

    private synchronized void incrementIdCount() {
        this.countId++;

    }

    private long getIdCount() {
        return this.countId;
    }

    public TreemapNode getRootNode() {
        return this.rootNode;
    }

    public void setRoot(TreemapNode root) {
        this.rootNode = root;

    }

    public Hashtable<String, TreemapNode> getTreeMap() {
        return this.treeMap;
    }

} public class ServerController {

    public static final String URL = "http://localhost:" + EmbeddedServer.getPort() + "/index.jsp";
    private static final Log logger = LogFactory.getLog(ServerController.class);

    public static void bind(final EventBus eventbus) {
        eventbus.addHandler(StartScanEvent.TYPE, new StartScanEventHandler() {

            @Override
            public String getId() {
                return getClass().getCanonicalName() + ": " + StartScanEventHandler.class.getName();
            }

            @Override
            public void handle(File toScan) {
                EmbeddedServer server = new EmbeddedServer(eventbus);
                try {
                    logger.info("Starting jetty server...");
                    server.startServer();
                    logger.info("opening web browser...");
                    java.awt.Desktop.getDesktop().browse(java.net.URI.create(URL));
                } catch (Exception e) {
                	logger.error("Error lauching the server", e);
                }

            }
        });
    }
}
import java.io.File;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.antelink.sourcesquare.client.scan.ScanStatus;
import com.antelink.sourcesquare.client.scan.ScanStatusManager;
import com.antelink.sourcesquare.client.scan.SourceSquareEngine;
import com.antelink.sourcesquare.client.scan.SourceSquareFSWalker;
import com.antelink.sourcesquare.event.base.EventBus;
import com.antelink.sourcesquare.event.events.StartScanEvent;
import com.antelink.sourcesquare.gui.controller.ExitController;
import com.antelink.sourcesquare.gui.controller.SourceSquareController;
import com.antelink.sourcesquare.gui.view.ExitSourceSquareView;
import com.antelink.sourcesquare.gui.view.SourceSquareView;
import com.antelink.sourcesquare.query.AntepediaQuery;
import com.antelink.sourcesquare.results.ResultBuilder;
import com.antelink.sourcesquare.results.TreeMapBuilder;
import com.antelink.sourcesquare.server.ServerController;
/**
 * Copyright (C) 2009-2012 Antelink SAS
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License Version 3 as published
 * by the Free Software Foundation.
 *
 * This program 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 Affero General Public License Version 3
 * for more details.
 *
 * You should have received a copy of the GNU Affero General Public License Version
 * 3 along with this program. If not, see http://www.gnu.org/licenses/agpl.html
 *
 * Additional permission under GNU AGPL version 3 section 7
 *
 * If you modify this Program, or any covered work, by linking or combining it with
 * Eclipse Java development tools (JDT) or Jetty (or a modified version of these
 * libraries), containing parts covered by the terms of Eclipse Public License 1.0,
 * the licensors of this Program grant you additional permission to convey the
 * resulting work. Corresponding Source for a non-source form of such a combination
 * shall include the source code for the parts of Eclipse Java development tools
 * (JDT) or Jetty used as well as that of the covered work.
 */
package com.antelink.sourcesquare;





public class SourceSquare {

    private final static Log logger = LogFactory.getLog(SourceSquare.class);

    public static void main(String[] args) {

        logger.debug("starting.....");

        final EventBus eventBus = new EventBus();

        AntepediaQuery query = new AntepediaQuery();

        SourceSquareEngine engine = new SourceSquareEngine(eventBus, query);

        ScanStatusManager manager = new ScanStatusManager(eventBus);
        manager.bind();

        TreeMapBuilder treemap = new TreeMapBuilder(eventBus);
        treemap.bind();

        ResultBuilder builder = new ResultBuilder(eventBus, treemap);
        builder.bind();

        final SourceSquareFSWalker walker = new SourceSquareFSWalker(engine, eventBus, treemap);
        walker.bind();

        ServerController.bind(eventBus);
        if (args.length != 0) {
            final File toScan = new File(args[0]);

            if (!toScan.isDirectory()) {
                logger.error("The argument is not a directory");
                logger.info("exiting SourceSquare");
                System.exit(0);
            }

            eventBus.fireEvent(new StartScanEvent(toScan));