OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 153 | Blame | Compare with Previous | Last modification | View Log | RSS feed

package org.openconcerto.modules.badge;

import java.awt.AWTException;
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.sql.SQLException;
import java.sql.Time;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;

import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.core.customerrelationship.customer.element.CustomerSQLElement;
import org.openconcerto.erp.modules.ModuleVersion;
import org.openconcerto.erp.utils.HeadlessGestion;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.utils.cc.ITransformer;

public class BadgeListener implements Runnable {
    private static final int UDP_PORT = 1470;

    private String doorIp;
    private int relai;
    private ComptaPropsConfiguration conf;
    private Preferences modulePrefs;

    protected TrayIcon trayIcon;

    public BadgeListener() {

    }

    public void init(String id) throws Exception {
        final HeadlessGestion headlessGestion = new HeadlessGestion();
        headlessGestion.setupGlobalState(2, Integer.valueOf(id));
        this.conf = headlessGestion.getComptaPropsConfiguration();

        final String moduleID = "org.openconcerto.modules.badge";
        final ModuleVersion vers = this.conf.getModuleManager().getDBInstalledModuleVersion(moduleID);
        this.modulePrefs = this.conf.getModuleManager().getFactories().get(moduleID).get(vers).getSQLPreferences(this.conf.getModuleManager().getRoot());
    }

    private PopupMenu createTrayMenu() {
        ActionListener exitListener = new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.out.println("Bye from the tray");
                System.exit(0);
            }
        };

        ActionListener executeListener = new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                openDoor(4);
            }
        };

        PopupMenu menu = new PopupMenu();
        MenuItem execItem = new MenuItem("Ouvrir la porte");
        execItem.addActionListener(executeListener);
        menu.add(execItem);

        MenuItem exitItem = new MenuItem("Quitter");
        exitItem.addActionListener(exitListener);
        menu.add(exitItem);
        return menu;
    }

    private TrayIcon createTrayIcon() {
        Image image = new ImageIcon(this.getClass().getResource("badge.png")).getImage();
        PopupMenu popup = createTrayMenu();
        TrayIcon ti = new TrayIcon(image, "Service de badge", popup);
        ti.setImageAutoSize(true);
        return ti;
    }

    public static void main(String[] args) throws Exception {
        BadgeListener bl = new BadgeListener();
        bl.readConfiguration();
        bl.initUI();
        bl.startDaemon();
    }

    public void startDaemon() {
        Thread t = new Thread(this);
        t.setName("UDP Listener");
        t.start();
    }

    public void initUI() {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                if (!SystemTray.isSupported()) {
                    try {
                        JOptionPane.showMessageDialog(new JFrame(), "System tray not supported on this platform");
                    } catch (Exception e) {
                        System.out.println("System tray not supported on this platform");
                    }
                } else {
                    try {
                        final SystemTray sysTray = SystemTray.getSystemTray();
                        trayIcon = createTrayIcon();
                        sysTray.add(trayIcon);
                        displayMessage("Service de badge", "Ecoute sur port " + UDP_PORT);
                    } catch (AWTException e) {
                        System.out.println("Unable to add icon to the system tray");
                    }
                }

            }
        });

    }

    public void readConfiguration() throws Exception {
        final Properties props = new Properties();
        final File file = new File("badge.properties");
        System.out.println("Reading from: " + file.getAbsolutePath());
        try {
            final FileInputStream inStream = new FileInputStream(file);
            props.load(inStream);
            this.doorIp = props.getProperty("ip").trim();
            this.relai = Integer.parseInt(props.getProperty("relai", "1"));
            inStream.close();
        } catch (FileNotFoundException e) {
            JOptionPane.showMessageDialog(new JFrame(), "Fichier manquant\n" + file.getAbsolutePath());
        } catch (IOException e) {
            JOptionPane.showMessageDialog(new JFrame(), e.getMessage());
        }
        System.err.println("BadgeListener.readConfiguration() door ip : " + doorIp + ", index :" + relai);

        init(props.getProperty("idSociete"));
    }

    @Override
    public void run() {
        while (true) {
            DatagramSocket serverSocket = null;

            try {
                final byte[] receiveData = new byte[1024];
                serverSocket = new DatagramSocket(UDP_PORT);

                while (true) {
                    final DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
                    serverSocket.receive(receivePacket);
                    final String sentence = new String(receivePacket.getData()).trim();
                    cardIdReceived(sentence);
                }
            } catch (Throwable e) {
                e.printStackTrace();
                displayError("Erreur", (e == null) ? "" : e.getMessage());
            } finally {
                if (serverSocket != null) {
                    serverSocket.close();
                }
            }
            try {
                System.out.println("Waiting 10s");
                Thread.sleep(10 * 1000);
            } catch (InterruptedException e) {
                System.err.println(e.getMessage());
            }
        }
    }

    public void cardIdReceived(final String sentence) {
        if (isBadgeAllowed(sentence)) {
            boolean b = openDoor(4);
            if (b) {
                displayMessage("Ouverture", "Ouverture de la porte OK");
            } else {
                displayError("Erreur", "Impossible d'ouvrir la porte");
            }

        } else {
            displayMessage("Carte refusée", "Carte " + sentence + " non acceptée");
        }
    }

    private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);

    public void displayMessage(String title, String txt) {
        displayMessage(title, txt, TrayIcon.MessageType.INFO);
    }

    private void displayMessage(String title, String txt, final TrayIcon.MessageType msgType) {
        if (this.trayIcon != null) {
            this.trayIcon.displayMessage(title, txt, msgType);
        } else {
            System.out.println("[" + msgType.name() + "] " + DATE_FMT.format(LocalDateTime.now()) + " " + title + " : " + txt);
        }
    }

    public void displayError(String title, String txt) {
        displayMessage(title, txt, TrayIcon.MessageType.ERROR);
    }

    public boolean isBadgeAllowed(final String cardNumber) {
        final CustomerSQLElement clientElem = this.conf.getDirectory().getElement(CustomerSQLElement.class);
        final String clientAdhFieldName = "ID_ADHERENT";
        final SQLTable tableAdh = clientElem.getForeignElement(clientAdhFieldName).getTable();
        // TODO use createFetcher()
        final SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(clientElem.createGraph());
        fetcher.setSelTransf(new ITransformer<SQLSelect, SQLSelect>() {
            @Override
            public SQLSelect transformChecked(SQLSelect sel) {
                sel.andWhere(new Where(sel.getAlias(tableAdh).getField("NUMERO_CARTE"), "=", cardNumber));
                return sel;
            }
        });
        final List<SQLRowValues> list = fetcher.fetch();

        String motif = "";

        boolean allow = false;
        SQLRowValues adh = null;
        String name = null;
        // Aucun adhérent assigné à cette carte
        if (list == null || list.isEmpty()) {
            motif = "Aucun adhérent associé à la carte " + cardNumber;
            displayError("Erreur", motif);

        } else if (list.size() > 1) {
            motif = list.size() + " adhérents sont liés à la même carte " + cardNumber;
            displayError("Erreur", motif);
            Thread.dumpStack();
        } else {

            for (SQLRowValues clientR : list) {
                name = clientR.getString("NOM");
                adh = (SQLRowValues) clientR.getForeign(clientAdhFieldName);

                // Admin toujours autorisé
                if (adh.getBoolean("ADMIN")) {
                    allow = true;
                    motif = "Administrateur toujours autorisé";
                    break;
                }

                // get up to date values
                try {
                    this.modulePrefs.sync();
                } catch (BackingStoreException e) {
                    e.printStackTrace();
                }
                final boolean onlyAdmin = this.modulePrefs.getBoolean(Module.ENTREE_PREF, false);
                if (onlyAdmin) {
                    motif = "Seul les membres administrateurs sont autorisés!";
                    break;
                }

                if (!adh.getBoolean("ACTIF")) {
                    motif = "La carte de l'adhérent n'est pas active dans sa fiche";
                    break;
                }

                Calendar cal = Calendar.getInstance();
                final Date d = cal.getTime();
                final Calendar dateValidite = adh.getDate("DATE_VALIDITE_INSCRIPTION");

                if (dateValidite != null && dateValidite.before(cal)) {
                    motif = "La date d'autorisation est expirée";
                    break;
                }

                SQLRow rowPlage = adh.asRow().getForeignRow("ID_PLAGE_HORAIRE");

                if (rowPlage != null) {
                    Time time = new Time(cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND));
                    SimpleDateFormat dateFormat = new SimpleDateFormat("EEEE");
                    String day = dateFormat.format(d).toUpperCase();
                    {
                        Time d1 = (Time) rowPlage.getObject("DEBUT_1_" + day);
                        Time f1 = (Time) rowPlage.getObject("FIN_1_" + day);
                        if (d1 != null && f1 != null) {
                            if (time.after(d1) && time.before(f1)) {
                                allow = true;
                                motif = "Autorisé sur la plage " + rowPlage.getString("NOM") + " 1";
                                break;
                            }
                        }
                    }
                    {
                        Time d1 = (Time) rowPlage.getObject("DEBUT_2_" + day);
                        Time f1 = (Time) rowPlage.getObject("FIN_2_" + day);

                        if (d1 != null && f1 != null) {
                            if (time.after(d1) && time.before(f1)) {
                                allow = true;
                                motif = "Autorisé sur la plage " + rowPlage.getString("NOM") + " 2";
                                break;
                            }
                        }
                    }

                    {
                        Time d1 = (Time) rowPlage.getObject("DEBUT_3_" + day);
                        Time f1 = (Time) rowPlage.getObject("FIN_3_" + day);

                        if (d1 != null && f1 != null) {
                            if (time.after(d1) && time.before(f1)) {
                                allow = true;
                                motif = "Autorisé sur la plage " + rowPlage.getString("NOM") + " 3";
                                break;
                            }
                        }
                    }
                    motif = "Non autorisé sur la plage horaire " + rowPlage.getString("NOM");
                } else {
                    motif = "Aucune plage horaire associée";
                }
            }
        }

        // Création de l'entrée dans la table
        SQLTable tableEntree = this.conf.getDirectory().getElement("ENTREE").getTable();
        SQLRowValues rowVals = new SQLRowValues(tableEntree);
        rowVals.put("DATE", new Date());
        rowVals.put("NUMERO_CARTE", cardNumber);
        rowVals.put("ACCEPTE", allow);
        rowVals.put("MOTIF", motif);

        if (name != null) {
            rowVals.put("ADHERENT", name);
        }
        try {
            rowVals.commit();
        } catch (SQLException exn) {
            exn.printStackTrace();
        }
        return allow;
    }

    public boolean openDoor(int seconds) {
        final Relai r = new Relai(doorIp, relai);
        try {
            r.pulse(seconds);
            return true;
        } catch (Throwable ex) {
            return false;
        }
    }

    public String getDoorIp() {
        return doorIp;
    }
}