Code Sketch


graphic_7325
By: Mhalsakant School
Category: Art
import javax.swing._
import java.awt._
import java.awt.event._
import java.awt.print.PrinterException
import java.net.{URI, URL, HttpURLConnection}
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.io.{BufferedReader, InputStreamReader}
import java.util.Base64
import scala.collection.mutable.ArrayBuffer
import scala.util.Random

object RailwayApp {

  // ?. ??????? ??????? '7313' (Base64 Encoded)
  val hiddenSecret = "NzMxMw=="

  def getPassword(): String = {
    new String(Base64.getDecoder.decode(hiddenSecret), "UTF-8")
  }

  val cloudHistoryKey = "railway_school_history_7313"
  val cloudHistoryUrl = s"https://kvdb.io/4y9H7m5QzK7hS3qX9kH5Rz/$cloudHistoryKey"

  val trainList = Vector(
    ("12124", "Deccan Queen", "Pune Jn - Mumbai CSMT", 450),
    ("12127", "Intercity Express", "Mumbai CSMT - Pune Jn", 350),
    ("11010", "Sinhagad Express", "Pune Jn - Mumbai CSMT", 250),
    ("11030", "Koyna Express", "Mumbai CSMT - Kolhapur", 400),
    ("12025", "Shatabdi Express", "Pune - Secunderabad", 600),
    ("11007", "Deccan Express", "Mumbai CSMT - Pune Jn", 300)
  )

  val bookingHistory = ArrayBuffer[String]()
  val localHistory = ArrayBuffer[String]()
  var currentUser: String = "Guest"
  val random = new Random()

  def fetchCloudData(urlStr: String): String = {
    try {
      val url = new URL(urlStr)
      val conn = url.openConnection().asInstanceOf[HttpURLConnection]
      conn.setRequestMethod("GET")
      conn.setConnectTimeout(2000)
      conn.setReadTimeout(2000)

      if (conn.getResponseCode == 200) {
        val in = new BufferedReader(new InputStreamReader(conn.getInputStream, "UTF-8"))
        val sb = new StringBuilder
        var line = in.readLine()
        while (line != null) {
          sb.append(line).append("\n")
          line = in.readLine()
        }
        in.close()
        sb.toString().trim
      } else ""
    } catch {
      case _: Exception => ""
    }
  }

  def logToCloudHistory(record: String): Unit = {
    localHistory += record
    new Thread(new Runnable {
      def run(): Unit = {
        try {
          val oldLog = fetchCloudData(cloudHistoryUrl)
          val updated = if (oldLog.isEmpty) record else oldLog + "\n" + record
          val url = new URL(cloudHistoryUrl)
          val conn = url.openConnection().asInstanceOf[HttpURLConnection]
          conn.setRequestMethod("POST")
          conn.setDoOutput(true)
          conn.setConnectTimeout(2000)
          conn.setRequestProperty("Content-Type", "text/plain; charset=UTF-8")
          val os = conn.getOutputStream
          os.write(updated.getBytes("UTF-8"))
          os.flush()
          os.close()
          conn.getResponseCode
        } catch {
          case _: Exception =>
        }
      }
    }).start()
  }

  def openWebsite(url: String): Unit = {
    try {
      if (Desktop.isDesktopSupported) Desktop.getDesktop.browse(new URI(url))
      else JOptionPane.showMessageDialog(null, "Open this website:\n" + url)
    } catch {
      case _: Exception => JOptionPane.showMessageDialog(null, "Website could not be opened:\n" + url)
    }
  }

  // ----------------------------------------
  // 1. SPLASH SCREEN (TRAIN DESIGN)
  // ----------------------------------------
  def showSplash(): Unit = {
    val splash = new JFrame()
    splash.setUndecorated(true)
    splash.setSize(600, 380)
    splash.setLocationRelativeTo(null)

    val logoPanel = new JPanel() {
      override def paintComponent(g: Graphics): Unit = {
        super.paintComponent(g)
        val g2 = g.asInstanceOf[Graphics2D]
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)

        // Background
        g2.setColor(new Color(15, 32, 67))
        g2.fillRect(0, 0, getWidth, getHeight)

        // Pantograph
        g2.setColor(new Color(200, 200, 210))
        g2.setStroke(new BasicStroke(3))
        g2.drawLine(250, 42, 350, 42)
        g2.drawLine(270, 42, 300, 68)
        g2.drawLine(330, 42, 300, 68)
        g2.drawLine(300, 68, 275, 78)
        g2.drawLine(300, 68, 325, 78)

        // Locomotive Body
        g2.setColor(new Color(178, 34, 34))
        g2.fillRoundRect(220, 78, 160, 130, 28, 28)
        g2.setColor(new Color(139, 0, 0))
        g2.fillRoundRect(225, 75, 150, 20, 15, 15)

        // Windows
        g2.setColor(new Color(190, 225, 255))
        g2.fillRoundRect(235, 95, 60, 36, 10, 10)
        g2.fillRoundRect(305, 95, 60, 36, 10, 10)
        g2.setColor(new Color(40, 40, 40))
        g2.setStroke(new BasicStroke(2))
        g2.drawRoundRect(235, 95, 60, 36, 10, 10)
        g2.drawRoundRect(305, 95, 60, 36, 10, 10)

        // Yellow Stripe & Lights
        g2.setColor(new Color(255, 193, 7))
        g2.fillRect(220, 142, 160, 14)
        g2.setColor(new Color(40, 40, 40))
        g2.fillOval(282, 134, 36, 30)
        g2.setColor(new Color(255, 255, 200))
        g2.fillOval(286, 138, 13, 22)
        g2.fillOval(301, 138, 13, 22)
        g2.setColor(Color.RED)
        g2.fillOval(235, 175, 12, 12)
        g2.fillOval(353, 175, 12, 12)

        // Buffers & Tracks
        g2.setColor(new Color(30, 30, 30))
        g2.fillRect(215, 205, 170, 12)
        g2.fillOval(230, 202, 18, 18)
        g2.fillOval(352, 202, 18, 18)

        g2.setColor(new Color(200, 200, 210))
        g2.setStroke(new BasicStroke(4))
        g2.drawLine(150, 230, 450, 230)
        g2.drawLine(120, 246, 480, 246)

        g2.setColor(new Color(130, 110, 90))
        g2.setStroke(new BasicStroke(3))
        var sx = 140
        while (sx <= 460) {
          g2.drawLine(sx, 226, sx - 8, 250)
          sx += 26
        }

        // Title Texts
        g2.setColor(Color.WHITE)
        g2.setFont(new Font("Arial", Font.BOLD, 26))
        val title = "INDIAN RAILWAYS"
        val fmTitle = g2.getFontMetrics
        g2.drawString(title, (getWidth - fmTitle.stringWidth(title)) / 2, 285)

        g2.setFont(new Font("Arial", Font.PLAIN, 15))
        g2.setColor(new Color(255, 193, 7))
        val sub = "TRAIN INFORMATION & BOOKING APP"
        val fmSub = g2.getFontMetrics
        g2.drawString(sub, (getWidth - fmSub.stringWidth(sub)) / 2, 312)

        g2.setFont(new Font("Arial", Font.ITALIC, 13))
        g2.setColor(new Color(180, 210, 240))
        val load = "Starting engine..."
        val fmLoad = g2.getFontMetrics
        g2.drawString(load, (getWidth - fmLoad.stringWidth(load)) / 2, 345)
      }
    }

    splash.setContentPane(logoPanel)
    splash.setVisible(true)

    val splashTimer = new javax.swing.Timer(1500, new ActionListener {
      def actionPerformed(e: ActionEvent): Unit = {
        splash.dispose()
        showLogin()
      }
    })
    splashTimer.setRepeats(false)
    splashTimer.start()
  }

  // ----------------------------------------
  // 2. DIRECT LOGIN SCREEN
  // ----------------------------------------
  def showLogin(): Unit = {
    val login = new JFrame("Indian Railway - Login")
    login.setSize(480, 360)
    login.setLocationRelativeTo(null)
    login.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE)

    val panel = new JPanel(new GridLayout(0, 1, 8, 8))
    panel.setBorder(BorderFactory.createEmptyBorder(20, 35, 20, 35))
    panel.setBackground(new Color(235, 244, 255))

    val title = new JLabel("INDIAN RAILWAY LOGIN", SwingConstants.CENTER)
    title.setFont(new Font("Arial", Font.BOLD, 22))

    val userLabel = new JLabel("Username:")
    userLabel.setFont(new Font("Arial", Font.BOLD, 14))
    val userField = new JTextField()
    userField.setFont(new Font("Arial", Font.PLAIN, 16))

    val passLabel = new JLabel("Password:")
    passLabel.setFont(new Font("Arial", Font.BOLD, 14))
    val passwordField = new JPasswordField()
    passwordField.setFont(new Font("Arial", Font.PLAIN, 16))

    val loginButton = new JButton("LOGIN")
    loginButton.setFont(new Font("Arial", Font.BOLD, 16))
    loginButton.setBackground(new Color(20, 80, 150))
    loginButton.setForeground(Color.WHITE)
    loginButton.setFocusPainted(false)

    panel.add(title)
    panel.add(userLabel)
    panel.add(userField)
    panel.add(passLabel)
    panel.add(passwordField)
    panel.add(loginButton)

    login.setContentPane(panel)

    def checkPassword(): Unit = {
      val usernameInput = userField.getText.trim
      val enteredPass = new String(passwordField.getPassword).trim

      if (usernameInput.isEmpty) {
        JOptionPane.showMessageDialog(login, "Please enter your Username.", "Missing Details", JOptionPane.WARNING_MESSAGE)
      } else if (enteredPass.isEmpty) {
        JOptionPane.showMessageDialog(login, "Please enter Password.", "Missing Details", JOptionPane.WARNING_MESSAGE)
      } else {
        val timeFormat = DateTimeFormatter.ofPattern("dd-MM-yyyy hh:mm:ss a")
        val logTime = LocalDateTime.now().format(timeFormat)

        // ??????? '7313' ??????
        if (enteredPass == getPassword()) {
          currentUser = usernameInput
          logToCloudHistory(s"User: $currentUser | Time: $logTime | Status: SUCCESS")
          login.dispose()
          openMainApp()
        } else {
          logToCloudHistory(s"User: $usernameInput | Time: $logTime | Status: FAILED ATTEMPT")
          passwordField.setText("")
          JOptionPane.showMessageDialog(
            login,
            "Incorrect password! Please try again.",
            "Login Failed",
            JOptionPane.ERROR_MESSAGE
          )
        }
      }
    }

    loginButton.addActionListener(new ActionListener {
      def actionPerformed(e: ActionEvent): Unit = checkPassword()
    })

    passwordField.addActionListener(new ActionListener {
      def actionPerformed(e: ActionEvent): Unit = checkPassword()
    })

    login.setVisible(true)
  }

  // ----------------------------------------
  // 3. MAIN APPLICATION SCREEN
  // ----------------------------------------
  def openMainApp(): Unit = {
    val app = new JFrame("Indian Railway Information App")
    app.setSize(960, 780)
    app.setLocationRelativeTo(null)
    app.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE)

    val root = new JPanel(new BorderLayout(12, 12))
    root.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12))
    root.setBackground(new Color(235, 244, 255))

    val topPanel = new JPanel(new GridLayout(2, 1, 4, 4))
    topPanel.setBackground(new Color(235, 244, 255))

    val heading = new JLabel("INDIAN RAILWAY INFORMATION", SwingConstants.CENTER)
    heading.setFont(new Font("Arial", Font.BOLD, 24))
    heading.setForeground(new Color(15, 65, 125))

    val userTag = new JLabel(s"Logged in as: $currentUser", SwingConstants.CENTER)
    userTag.setFont(new Font("Arial", Font.BOLD, 14))
    userTag.setForeground(new Color(40, 110, 40))

    topPanel.add(heading)
    topPanel.add(userTag)
    root.add(topPanel, BorderLayout.NORTH)

    val output = new JTextArea()
    output.setEditable(false)
    output.setFont(new Font("Monospaced", Font.PLAIN, 15))
    output.setLineWrap(true)
    output.setWrapStyleWord(true)
    output.setMargin(new Insets(10, 10, 10, 10))

    val scroll = new JScrollPane(output)
    scroll.setPreferredSize(new Dimension(920, 360))
    root.add(scroll, BorderLayout.CENTER)

    val buttons = new JPanel(new GridLayout(5, 2, 8, 8))
    buttons.setPreferredSize(new Dimension(920, 240))
    buttons.setBackground(new Color(235, 244, 255))

    def showText(s: String): Unit = {
      output.setText(s)
      output.setCaretPosition(0)
    }

    def addButton(label: String, bgColor: Color = new Color(25, 90, 165))(action: => Unit): Unit = {
      val b = new JButton(label)
      b.setFont(new Font("Arial", Font.BOLD, 13))
      b.setBackground(bgColor)
      b.setForeground(Color.WHITE)
      b.setFocusPainted(false)
      b.addActionListener(new ActionListener {
        def actionPerformed(e: ActionEvent): Unit = action
      })
      buttons.add(b)
    }

    def makePNR(): String = "DEMO" + (100000 + random.nextInt(900000)).toString

    // 1. TRAIN SEARCH
    addButton("1. Train Search") {
      val query = JOptionPane.showInputDialog(app, "Enter Train No, Name, or Station (e.g., Pune / 12124 / Queen):", "Train Search", JOptionPane.QUESTION_MESSAGE)
      if (query != null) {
        val trimmed = query.trim.toLowerCase
        if (trimmed.isEmpty) showText("Please enter a valid search term.")
        else {
          val found = trainList.filter { case (num, name, route, _) =>
            num.toLowerCase.contains(trimmed) || name.toLowerCase.contains(trimmed) || route.toLowerCase.contains(trimmed)
          }
          if (found.nonEmpty) {
            val resultText =
              "====================================================\n" +
              "                TRAIN SEARCH RESULTS                \n" +
              "====================================================\n\n" +
              found.map { case (num, name, route, fare) =>
                s"Train Number : $num\nTrain Name   : $name\nRoute        : $route\nSample Fare  : Rs. $fare"
              }.mkString("\n\n----------------------------------------------------\n\n") +
              "\n\n====================================================\n" +
              s"Total trains found: ${found.size}"
            showText(resultText)
          } else {
            showText(s"No train found matching: \"$query\"")
          }
        }
      }
    }

    // 2. ALL TRAINS
    addButton("2. All Trains") {
      showText(
        "====================================================\n" +
        "                 SAMPLE TRAIN LIST                  \n" +
        "====================================================\n\n" +
        trainList.map { case (num, name, route, fare) =>
          s"Train No: $num - $name\nRoute   : $route\nFare    : Rs. $fare"
        }.mkString("\n\n----------------------------------------------------\n\n")
      )
    }

    // 3. LIVE STATUS
    addButton("3. Live Train Status") {
      showText("Opening NTES railway website...")
      openWebsite("https://enquiry.indianrail.gov.in/ntes/")
    }

    // 4. ROUTE AND DEMO BOOKING
    addButton("4. Route & Booking") {
      val from = JOptionPane.showInputDialog(app, "From station (e.g. Pune Jn):")
      if (from != null && from.trim.nonEmpty) {
        val to = JOptionPane.showInputDialog(app, "To station (e.g. Mumbai CSMT):")
        if (to != null && to.trim.nonEmpty) {
          val date = JOptionPane.showInputDialog(app, "Journey date (DD-MM-YYYY):")
          if (date != null && date.trim.nonEmpty) {
            val passenger = JOptionPane.showInputDialog(app, "Passenger name:")
            if (passenger != null && passenger.trim.nonEmpty) {
              val ageText = JOptionPane.showInputDialog(app, "Passenger age:")
              val countText = JOptionPane.showInputDialog(app, "Number of tickets (1 to 6):")
              try {
                val age = ageText.trim.toInt
                val count = countText.trim.toInt
                if (age < 1 || age > 120 || count < 1 || count > 6) throw new IllegalArgumentException()
                val pnr = makePNR()
                val fare = count * 350
                val ticket =
                  "====================================\n" +
                  "       RAILWAY DEMO E-TICKET        \n" +
                  "====================================\n\n" +
                  s"Booked By  : $currentUser\n" +
                  s"Demo PNR   : $pnr\n" +
                  s"Passenger  : ${passenger.trim}\n" +
                  s"Age        : $age\n" +
                  s"From       : ${from.trim}\n" +
                  s"To         : ${to.trim}\n" +
                  s"Date       : ${date.trim}\n" +
                  s"Tickets    : $count\n" +
                  s"Sample fare: Rs. $fare\n\n" +
                  "Status: DEMO BOOKING SUCCESSFUL\n" +
                  "===================================="
                bookingHistory += ticket
                showText(ticket)
                JOptionPane.showMessageDialog(app, s"DEMO BOOKING SUCCESSFUL!\n\nDemo PNR: $pnr")
              } catch {
                case _: Exception => JOptionPane.showMessageDialog(app, "Please enter a valid age and ticket count.")
              }
            }
          }
        }
      }
    }

    // 5. BOOKING HISTORY
    addButton("5. Booking History") {
      if (bookingHistory.isEmpty) showText("No demo bookings yet.")
      else showText(bookingHistory.zipWithIndex.map { case (t, i) => s"BOOKING #${i + 1}\n$t" }.mkString("\n\n"))
    }

    // 6. PRINT TICKET
    addButton("6. Print Current Ticket") {
      if (output.getText.contains("RAILWAY DEMO E-TICKET")) {
        try { output.print() } catch { case ex: PrinterException => JOptionPane.showMessageDialog(app, "Printing failed: " + ex.getMessage) }
      } else JOptionPane.showMessageDialog(app, "Create a demo ticket first.")
    }

    // 7. OFFICIAL WEBSITE
    addButton("7. Official Ticket Booking") {
      showText("Opening official IRCTC booking website...")
      openWebsite("https://www.irctc.co.in/nget/train-search")
    }

    // 8. CLEAR SCREEN
    addButton("8. Home / Clear Screen") {
      showText(s"WELCOME TO INDIAN RAILWAY APP, $currentUser!\n\nSelect an option below to proceed.")
    }

    // 9. ADMIN LOGIN HISTORY (????? '7313' ????????? ?????)
    addButton("9. Admin Login History", new Color(110, 45, 140)) {
      val pwdField = new JPasswordField()
      val dialog = JOptionPane.showConfirmDialog(
        app,
        Array[Object]("Enter Secret History Password:", pwdField),
        "Admin Access Required",
        JOptionPane.OK_CANCEL_OPTION,
        JOptionPane.WARNING_MESSAGE
      )

      if (dialog == JOptionPane.OK_OPTION) {
        val enteredSecret = new String(pwdField.getPassword).trim

        if (enteredSecret == getPassword()) {
          showText("Fetching latest records...")
          new Thread(new Runnable {
            def run(): Unit = {
              val remoteData = fetchCloudData(cloudHistoryUrl)
              val allData = if (remoteData.trim.nonEmpty) remoteData else localHistory.mkString("\n")
              SwingUtilities.invokeLater(new Runnable {
                def run(): Unit = {
                  if (allData.trim.isEmpty) {
                    showText("No login records found yet.")
                  } else {
                    val formatted = allData.split("\n").zipWithIndex.map { case (rec, i) =>
                      s"[#${i + 1}] $rec"
                    }.mkString("\n----------------------------------------------------\n")

                    showText(
                      "====================================================\n" +
                      "         ADMIN LOGS: USER LOGIN RECORDS             \n" +
                      "====================================================\n\n" +
                      formatted +
                      "\n\n===================================================="
                    )
                  }
                }
              })
            }
          }).start()
        } else {
          JOptionPane.showMessageDialog(app, "Access Denied: Incorrect secret password!", "Unauthorized", JOptionPane.ERROR_MESSAGE)
        }
      }
    }

    // 10. LOGOUT BUTTON
    addButton("10. Logout", new Color(180, 40, 40)) {
      val confirm = JOptionPane.showConfirmDialog(app, s"Do you want to log out, $currentUser?", "Confirm Logout", JOptionPane.YES_NO_OPTION)
      if (confirm == JOptionPane.YES_OPTION) {
        app.dispose()
        showLogin()
      }
    }

    root.add(buttons, BorderLayout.SOUTH)
    showText(s"Welcome, $currentUser!\n\nChoose an option below to proceed.")
    app.setContentPane(root)
    app.setVisible(true)
  }

  def start(): Unit = {
    showSplash()
  }
}

RailwayApp.start()