package com.its.dsrc;

import com.its.app.utils.OS;
import com.its.app.utils.SysUtils;
import com.its.dsrc.config.ApplicationConfig;
import com.its.dsrc.config.RunningConfig;
import com.its.dsrc.entity.TbUnitSyst;
import com.its.dsrc.global.AppRepository;
import com.its.dsrc.process.DbmsDataProcess;
import com.its.dsrc.service.MultimediaService;
import com.its.dsrc.service.RseCtlrService;
import com.its.dsrc.service.RseSectService;
import com.its.dsrc.service.UnitSystService;
import com.its.dsrc.ui.JTextAreaOutputStream;
import com.its.dsrc.ui.MainUI;
import com.its.dsrc.xnettcp.center.CenterTcpServerService;
import com.its.dsrc.xnettcp.dsrc.DsrcTcpCommServerService;
import com.its.dsrc.xnettcp.dsrc.process.TcpServerDataProcess;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.Banner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.ApplicationPidFileWriter;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.annotation.EnableAsync;

import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.nio.charset.Charset;

@Slf4j
@EnableAsync
@Configuration
@SpringBootApplication
@RequiredArgsConstructor
@ComponentScan(basePackages = {"com.its.dsrc.config", "com.its.dsrc.dao.mapper", "com.its"})
public class DsrcCommServerApplication implements CommandLineRunner, ApplicationListener<ContextClosedEvent>, InitializingBean, DisposableBean {

    private final ApplicationConfig applicationConfig;
    private final RunningConfig runningConfig;
    private final AppRepository appRepository;
    private final DbmsDataProcess dbmsDataProcess;
    private final TcpServerDataProcess tcpServerDataProcess;
    private final UnitSystService unitSystService;
    private final RseCtlrService rseCtlrService;
    private final RseSectService rseSectService;
    private final MultimediaService multimediaService;
    private final DsrcTcpCommServerService dsrcTcpCommServerService;
    private final CenterTcpServerService centerTcpServerService;

    private static final String APPLICATION_NAME = "dsrc-comm-server";
    private static ConfigurableApplicationContext context = null;

    public static void main(String[] args) {
        System.setProperty("file.encoding","UTF-8");
        try {
            Field charset = Charset.class.getDeclaredField("defaultCharset");
            charset.setAccessible(true);
            charset.set(null,null);
        } catch(Exception e){
        }

        File file1 = new File("./conf/" + APPLICATION_NAME + ".pid");
        if (file1.exists()) {
            System.out.println(System.getProperty("Program Already Running....."));
            log.error("Program Already Running.....");
        }

        if (OS.isWindows() || OS.isMac()) {
            context = new SpringApplicationBuilder(DsrcCommServerApplication.class)
                    //.web(WebApplicationType.NONE)
                    .listeners(new ApplicationPidFileWriter("./conf/" + APPLICATION_NAME + ".pid"))
                    .headless(false)
                    .bannerMode(Banner.Mode.OFF)
                    .run(args);
        } else {
            SpringApplication application = new SpringApplicationBuilder()
                    .sources(DsrcCommServerApplication.class)
                    .listeners(new ApplicationPidFileWriter("./conf/" + APPLICATION_NAME + ".pid"))
                    .build();
            application.setBannerMode(Banner.Mode.OFF);
            application.run(args);
        }
    }

    @Override
    public void run(String... args) throws Exception {

//        ApplicationConfig applicationConfig = (ApplicationConfig) AppUtils.getBean(ApplicationConfig.class);
//        RunningConfig runningConfig = (RunningConfig)AppUtils.getBean(RunningConfig.class);
//        AppRepository appRepository = (AppRepository)AppUtils.getBean(AppRepository.class);

        if (OS.isWindows() || OS.isMac()) {
            String sysTime = SysUtils.getSysTimeStr();
            //JFrame.setDefaultLookAndFeelDecorated(true);
            JFrame frame = new JFrame("DSRC 통신 서버 - [" + sysTime + "]");
            MainUI mainUI = new MainUI(frame, appRepository);
            mainUI.updateBindPort(runningConfig.getCommBindingPort());
            SwingUtilities.invokeLater(() -> {
                try {
                    ClassPathResource file = new ClassPathResource("static/image/application.png");
                    URL imgURL = file.getURL();
                    frame.setIconImage(new ImageIcon(imgURL).getImage());
                } catch (IOException e) {
                    log.error("Not found application icon image");
                }
                frame.setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE);
                frame.setContentPane(mainUI.getRootPanel());
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.addWindowListener(new WindowAdapter() {
                    @Override
                    public void windowClosing(WindowEvent e) {
                        if (JOptionPane.showConfirmDialog(frame, "DSRC 통신서버 프로그램을 종료 하시겠습니까?", "프로그램 종료", JOptionPane.YES_NO_OPTION) == 0) {
                            if (context != null) {
                                int exitCode = SpringApplication.exit(context, () -> 0);
                                System.exit(exitCode);
                            } else {
                                // 컨텍스트가 없는 경우 강제 종료 (예외 상황)
                                System.exit(0);
                            }
                        } else {
                            frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
                        }
                    }
                });
                frame.pack();
                frame.setBounds(100, 100, 800, 920);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                JTextArea logArea = mainUI.getTaLog();
                logArea.setText(null);
                JTextAreaOutputStream out = new JTextAreaOutputStream(logArea);
                System.setOut(new PrintStream(out));
            });
        }

        log.info("");
        log.info("");
        log.info("************************************************************************************");
        log.info("**                                                                                **");
        log.info("**                         Intelligent Traffic System                             **");
        log.info("**                  DSRC(ASN.1) Communication Server Program.                     **");
        log.info("**                                                                                **");
        log.info("**                                                                   [ver.1.0]    **");
        log.info("**          {}", applicationConfig.getId());
        log.info("** startup: {}", applicationConfig.getBootingDateTime());
        log.info("************************************************************************************");

        // init application
//        DbmsDataProcess dbmsDataProcess = (DbmsDataProcess)AppUtils.getBean(DbmsDataProcess.class);
        dbmsDataProcess.run();

//        TcpServerDataProcess tcpServerDataProcess = (TcpServerDataProcess)AppUtils.getBean(TcpServerDataProcess.class);
        tcpServerDataProcess.run();

//        UnitSystService unitSystService = (UnitSystService)AppUtils.getBean(UnitSystService.class);
        unitSystService.loadMaster();
        unitSystService.updateUnitSystStts(true);
        TbUnitSyst unit = unitSystService.getUnitSystMap().get(applicationConfig.getId());
        if (unit != null) {
            applicationConfig.setListenPort(unit.getPRGM_PORT());
        }

//        RseCtlrService rseCtlrService = (RseCtlrService)AppUtils.getBean(RseCtlrService.class);
        rseCtlrService.loadDb();
        rseCtlrService.updateCtlrStts(true);

//        RseSectService rseSectService = (RseSectService)AppUtils.getBean(RseSectService.class);
        rseSectService.loadMaster();

//        MultimediaService multimediaService = (MultimediaService)AppUtils.getBean(MultimediaService.class);
        multimediaService.loadMaster();

        applicationConfig.setControllerBindingPort(runningConfig.getCommBindingPort());

        // schedule enable
        applicationConfig.setStartSchedule(true);

        if (OS.isWindows() || OS.isMac()) {
            MainUI mainUI = MainUI.getInstance();
            if (mainUI != null) {
                mainUI.loadControllerInfo();
            }
        }

//        DsrcTcpCommServerService dsrcTcpCommServerService = (DsrcTcpCommServerService)AppUtils.getBean(DsrcTcpCommServerService.class);
        dsrcTcpCommServerService.run();

//        CenterTcpServerService centerTcpServerService = (CenterTcpServerService)AppUtils.getBean(CenterTcpServerService.class);
        centerTcpServerService.run();
    }

    public void terminateApplication() {
//        CenterTcpServerService centerTcpServerService = (CenterTcpServerService)AppUtils.getBean(CenterTcpServerService.class);
        try {
            log.error("Application Terminated: center communication stop.");
            centerTcpServerService.stop();
        } catch (Exception e) {
            // no logging
        }

//        DsrcTcpCommServerService dsrcTcpCommServerService = (DsrcTcpCommServerService)AppUtils.getBean(DsrcTcpCommServerService.class);
        try {
            log.error("Application Terminated: dsrc communication stop.");
            dsrcTcpCommServerService.stop();
        } catch (Exception e) {
            // no logging
        }

//        RseCtlrService rseCtlrService = (RseCtlrService) AppUtils.getBean(RseCtlrService.class);
        try {
            log.error("Application Terminated: controller state update.");
            rseCtlrService.updateCtlrStts(false);
        } catch (Exception e) {
            // no logging
        }

//        UnitSystService unitSystService = (UnitSystService) AppUtils.getBean(UnitSystService.class);
        try {
            log.error("Application Terminated: unit state update.");
            unitSystService.updateUnitSystStts(false);
        } catch (Exception e) {
            // no logging
        }
    }
    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        log.error("Application Terminated: {}", event.getTimestamp());
        terminateApplication();
    }
    @Override
    public void afterPropertiesSet() throws Exception {
    }
    @Override
    public void destroy() throws Exception {
    }

}
