Index: .idea/.gitignore
===================================================================
--- .idea/.gitignore	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ .idea/.gitignore	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
Index: .idea/GlobeGuru.iml
===================================================================
--- .idea/GlobeGuru.iml	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ .idea/GlobeGuru.iml	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module version="4">
+  <component name="AdditionalModuleElements">
+    <content url="file://$MODULE_DIR$" />
+  </component>
+</module>
Index: .idea/compiler.xml
===================================================================
--- .idea/compiler.xml	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ .idea/compiler.xml	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="CompilerConfiguration">
+    <annotationProcessing>
+      <profile name="Maven default annotation processors profile" enabled="true">
+        <sourceOutputDir name="target/generated-sources/annotations" />
+        <sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
+        <outputRelativeToContentRoot value="true" />
+        <module name="GlobeGuru" />
+      </profile>
+    </annotationProcessing>
+  </component>
+</project>
Index: .idea/dataSources.xml
===================================================================
--- .idea/dataSources.xml	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ .idea/dataSources.xml	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="DataSourceManagerImpl" format="xml" multifile-model="true">
+    <data-source source="LOCAL" name="globe_guru" uuid="c6f8f0c5-7f6e-4a6d-9ff5-c09b974d248d">
+      <driver-ref>sqlite.xerial</driver-ref>
+      <synchronize>true</synchronize>
+      <jdbc-driver>org.sqlite.JDBC</jdbc-driver>
+      <jdbc-url>jdbc:sqlite:D:\Finki\Projects\GlobeGuru\globe_guru.db</jdbc-url>
+      <working-dir>$ProjectFileDir$</working-dir>
+      <libraries>
+        <library>
+          <url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/xerial/sqlite-jdbc/3.45.1.0/sqlite-jdbc-3.45.1.0.jar</url>
+        </library>
+        <library>
+          <url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar</url>
+        </library>
+      </libraries>
+    </data-source>
+  </component>
+</project>
Index: .idea/encodings.xml
===================================================================
--- .idea/encodings.xml	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ .idea/encodings.xml	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Encoding">
+    <file url="file://$PROJECT_DIR$/backend/GlobeGuru-backend/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/backend/GlobeGuru-backend/src/main/resources" charset="UTF-8" />
+  </component>
+</project>
Index: .idea/jarRepositories.xml
===================================================================
--- .idea/jarRepositories.xml	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ .idea/jarRepositories.xml	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="RemoteRepositoriesConfiguration">
+    <remote-repository>
+      <option name="id" value="central" />
+      <option name="name" value="Central Repository" />
+      <option name="url" value="https://repo.maven.apache.org/maven2" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="central" />
+      <option name="name" value="Maven Central repository" />
+      <option name="url" value="https://repo1.maven.org/maven2" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="jboss.community" />
+      <option name="name" value="JBoss Community repository" />
+      <option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
+    </remote-repository>
+  </component>
+</project>
Index: .idea/jsLibraryMappings.xml
===================================================================
--- .idea/jsLibraryMappings.xml	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ .idea/jsLibraryMappings.xml	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="JavaScriptLibraryMappings">
+    <file url="file://$PROJECT_DIR$" libraries="{font-awesome}" />
+    <file url="file://$PROJECT_DIR$/backend/GlobeGuru-backend" libraries="{font-awesome}" />
+  </component>
+</project>
Index: .idea/misc.xml
===================================================================
--- .idea/misc.xml	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ .idea/misc.xml	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,13 @@
+<project version="4">
+  <component name="ExternalStorageConfigurationManager" enabled="true" />
+  <component name="MavenProjectsManager">
+    <option name="originalFiles">
+      <list>
+        <option value="$PROJECT_DIR$/backend/GlobeGuru-backend/pom.xml" />
+      </list>
+    </option>
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/out" />
+  </component>
+</project>
Index: .idea/modules.xml
===================================================================
--- .idea/modules.xml	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ .idea/modules.xml	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/GlobeGuru.iml" filepath="$PROJECT_DIR$/.idea/GlobeGuru.iml" />
+    </modules>
+  </component>
+</project>
Index: .idea/uiDesigner.xml
===================================================================
--- .idea/uiDesigner.xml	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ .idea/uiDesigner.xml	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Palette2">
+    <group name="Swing">
+      <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
+      </item>
+      <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
+      </item>
+      <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
+        <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
+        <initial-values>
+          <property name="text" value="Button" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="RadioButton" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="CheckBox" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="Label" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+          <preferred-size width="200" height="200" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+          <preferred-size width="200" height="200" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
+      </item>
+      <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
+          <preferred-size width="-1" height="20" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
+      </item>
+      <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
+      </item>
+    </group>
+  </component>
+</project>
Index: .idea/vcs.xml
===================================================================
--- .idea/vcs.xml	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ .idea/vcs.xml	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="" vcs="Git" />
+  </component>
+</project>
Index: ckend/GlobeGuru-backend/frontend/css.css
===================================================================
--- backend/GlobeGuru-backend/frontend/css.css	(revision d4d8f6155e80421fe9fc8c1ee34e0b784226b96c)
+++ 	(revision )
@@ -1,45 +1,0 @@
-.option{
-    display: inline-flex;
-    justify-content: space-between;
-    width: 80%;
-    border: 1px solid black;
-    border-radius: 10px;
-    height: 300px;
-}
-.image{
-    width: 30%;
-    height: 100%;
-}
-p{
-    font-family: Arial;
-    font-size: 30px;
-}
-.btn{
-    margin-top: 120%;
-
-    display: inline-block;
-    outline: 0;
-    cursor: pointer;
-    border-radius: 8px;
-    box-shadow: 0 2px 5px 0 rgb(213 217 217 / 50%);
-    background: #FFD814;
-    border: 1px solid #FCD200;
-    font-size: 13px;
-    height: 31px;
-    padding: 0 11px;
-    text-align: center;
-    width: 100%;
-    min-width: 200px;
-    font-weight: 500;
-    color: #0F1111;
-    :hover{
-        background: #F7CA00;
-        border-color: #F2C200;
-        box-shadow: 0 2px 5px 0 rgb(213 217 217 / 50%);
-    }
-
-}
-#givenOptions{
-    width: 100%;
-    align-self: center;
-}
Index: ckend/GlobeGuru-backend/frontend/index.html
===================================================================
--- backend/GlobeGuru-backend/frontend/index.html	(revision d4d8f6155e80421fe9fc8c1ee34e0b784226b96c)
+++ 	(revision )
@@ -1,28 +1,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-    <meta charset="UTF-8">
-    <title>Title</title>
-    <link rel="stylesheet" href="css.css">
-</head>
-<body>
-<div class="searchBar">
-    <form id="form-id">
-        <label for="destination">Destination</label>
-        <input type="text" id="destination" name="destination">
-        <label for="departureDate">Departure Date</label>
-        <input type="date" id="departureDate" name="departureDate">
-        <label for="numberOfPeople">Number of People</label>
-        <input type="number" id="numberOfPeople" name="numberOfPeople">
-        <input type="submit">
-    </form>
-
-</div>
-<div id="givenOptions">
-    <!-- populated with JS response -->
-
-</div>
-
-<script src="js/formHandler.js">    </script>
-</body>
-</html>
Index: ckend/GlobeGuru-backend/frontend/js/formHandler.js
===================================================================
--- backend/GlobeGuru-backend/frontend/js/formHandler.js	(revision d4d8f6155e80421fe9fc8c1ee34e0b784226b96c)
+++ 	(revision )
@@ -1,82 +1,0 @@
-document.addEventListener('DOMContentLoaded', function() {
-    const form = document.getElementById('form-id'); // Ensure the form has the correct ID
-
-    form.addEventListener('submit', function(event) {
-        event.preventDefault(); // Prevent the default form submission
-
-        // Collect form data
-        const formData = new FormData(form);
-        const data = {};
-        formData.forEach((value, key) => {
-            data[key] = value;
-        });
-
-        // Send form data to the server
-        fetch('/submit', {
-            method: 'POST',
-            headers: {
-                'Content-Type': 'application/json'
-            },
-            body: JSON.stringify(data)
-        })
-            .then(response => response.json())
-            .then(data => {
-                // Process the scraped data and update the page
-                const dataList = document.getElementById('givenOptions');
-                dataList.innerHTML = ''; // Clear previous data
-
-                data.forEach(item => {
-                    // Create option container div
-                    const optionDiv = document.createElement('div');
-                    optionDiv.classList.add('option');
-
-                    // Create and append image element
-                    const img = document.createElement('img');
-                    img.classList.add('image');
-                    img.src = item.imgSrc; // Use item.imageSrc if available
-                    optionDiv.appendChild(img);
-
-                    // Create and append hotel name paragraph
-                    const nameParagraph = document.createElement('p');
-                    nameParagraph.id = 'name';
-                    nameParagraph.textContent = item.hotelName;
-                    optionDiv.appendChild(nameParagraph);
-
-                    // Create and append country paragraph
-                    const countryParagraph = document.createElement('p');
-                    countryParagraph.id = 'country';
-                    countryParagraph.style.fontSize = '20px';
-                    countryParagraph.textContent = item.country;
-                    optionDiv.appendChild(countryParagraph);
-
-                    // Create and append price heading and paragraph
-                    const priceHeading = document.createElement('h1');
-                    priceHeading.textContent = 'Цена:';
-                    optionDiv.appendChild(priceHeading);
-                    const priceParagraph = document.createElement('h2');
-                    priceParagraph.id = 'price';
-                    priceParagraph.textContent = item.price;
-                    optionDiv.appendChild(priceParagraph);
-
-                    // Create link and button
-                    const link = document.createElement('a');
-                    link.id = 'link';
-                    link.href = item.link; // Use item.link if available
-                    link.target = '_blank'; // Open link in new tab
-
-                    const button = document.createElement('button');
-                    button.classList.add('btn');
-                    button.textContent = 'Линк до страна';
-
-                    link.appendChild(button);
-                    optionDiv.appendChild(link);
-
-                    // Append option div to dataList
-                    dataList.appendChild(optionDiv);
-                });
-            })
-            .catch(error => {
-                console.error('Error fetching data:', error);
-            });
-    });
-});
Index: ckend/GlobeGuru-backend/frontend/package.json
===================================================================
--- backend/GlobeGuru-backend/frontend/package.json	(revision d4d8f6155e80421fe9fc8c1ee34e0b784226b96c)
+++ 	(revision )
@@ -1,6 +1,0 @@
-{
-  "name": "frontend",
-  "version": "1.0.0",
-  "dependencies": {
-  }
-}
Index: ckend/GlobeGuru-backend/frontend/results.html
===================================================================
--- backend/GlobeGuru-backend/frontend/results.html	(revision d4d8f6155e80421fe9fc8c1ee34e0b784226b96c)
+++ 	(revision )
@@ -1,13 +1,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-    <meta charset="UTF-8">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>Scraped Data Display</title>
-</head>
-<body>
-<h1>Scraped Data</h1>
-<ul id="scraped-data-list"></ul>
-
-</body>
-</html>
Index: backend/GlobeGuru-backend/pom.xml
===================================================================
--- backend/GlobeGuru-backend/pom.xml	(revision d4d8f6155e80421fe9fc8c1ee34e0b784226b96c)
+++ backend/GlobeGuru-backend/pom.xml	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -52,8 +52,49 @@
             <version>1.17.2</version>
         </dependency>
-
-
-
-
+        <dependency>
+            <groupId>org.xerial</groupId>
+            <artifactId>sqlite-jdbc</artifactId>
+            <version>3.34.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.api-client</groupId>
+            <artifactId>google-api-client</artifactId>
+            <version>1.30.10</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.auth</groupId>
+            <artifactId>google-auth-library-oauth2-http</artifactId>
+            <version>0.21.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.api-client</groupId>
+            <artifactId>google-api-client-gson</artifactId>
+            <version>1.30.10</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.http-client</groupId>
+            <artifactId>google-http-client</artifactId>
+            <version>1.36.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>2.0.16</version>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <version>2.0.16</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <version>3.1.0</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.websocket</groupId>
+            <artifactId>javax.websocket-all</artifactId>
+            <version>1.1</version>
+        </dependency>
     </dependencies>
 </project>
Index: backend/GlobeGuru-backend/src/main/java/AccountHandler.java
===================================================================
--- backend/GlobeGuru-backend/src/main/java/AccountHandler.java	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ backend/GlobeGuru-backend/src/main/java/AccountHandler.java	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,217 @@
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
+import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
+import com.google.api.client.http.HttpTransport;
+import com.google.api.client.http.javanet.NetHttpTransport;
+import com.google.api.client.json.JsonFactory;
+import com.google.api.client.json.jackson2.JacksonFactory;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.sql.SQLException;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class AccountHandler implements HttpHandler {
+
+    // Simple in-memory session management
+    private static final Map<String, String> sessions = new ConcurrentHashMap<>();
+    private static final String CLIENT_ID = "376204422797-s8f05nn6drmec1cko2h4kg1nk24abgc9.apps.googleusercontent.com";
+
+    @Override
+    public void handle(HttpExchange exchange) throws IOException {
+        String path = exchange.getRequestURI().getPath();
+        String method = exchange.getRequestMethod();
+
+        if ("POST".equalsIgnoreCase(method)) {
+            switch (path) {
+                case "/account/register":
+                    handleRegister(exchange);
+                    break;
+                case "/account/login":
+                    handleLogin(exchange);
+                    break;
+                case "/account/logout":
+                    handleLogout(exchange);
+                    break;
+                case "/account/delete":
+                    handleDeleteAccount(exchange);
+                    break;
+                default:
+                    Server.sendResponse(exchange, 404, "Endpoint not found");
+            }
+        } else if ("GET".equalsIgnoreCase(method) && path.equalsIgnoreCase("/account/session")) {
+            handleSession(exchange);
+        } else {
+            Server.sendResponse(exchange, 405, "Method not allowed");
+        }
+    }
+
+    private void handleSession(HttpExchange exchange) throws IOException {
+        String sessionId = getSessionId(exchange);
+        ObjectMapper mapper = new ObjectMapper();
+        Map<String, Object> response = new HashMap<>();
+        if (sessionId != null && sessions.containsKey(sessionId)) {
+            response.put("loggedIn", true);
+            response.put("user", sessions.get(sessionId));
+            try {
+                response.put("isAdmin", DatabaseUtil.isAdmin(sessions.get(sessionId)));
+            } catch (SQLException e) {
+                e.printStackTrace();
+                response.put("isAdmin", false);
+            }
+        } else {
+            response.put("loggedIn", false);
+        }
+
+        String jsonResponse = mapper.writeValueAsString(response);
+        Server.sendResponse(exchange, 200, jsonResponse);
+    }
+
+    private String getSessionId(HttpExchange exchange) {
+        List<String> cookies = exchange.getRequestHeaders().get("Cookie");
+        if (cookies != null) {
+            for (String cookie : cookies) {
+                if (cookie.contains("sessionId=")) {
+                    return cookie.replaceAll("g_state=\\{\"i_l\":0\\}; sessionId=", "");
+                }
+            }
+        }
+        return null;
+    }
+
+
+    private void handleRegister(HttpExchange exchange) throws IOException {
+        String requestBody = new String(exchange.getRequestBody().readAllBytes());
+        ObjectMapper mapper = new ObjectMapper();
+        Map<String, String> formData = mapper.readValue(requestBody, Map.class);
+        String username = formData.get("username");
+        String email = formData.get("email");
+        String password = formData.get("password");
+
+        try {
+            if (DatabaseUtil.registerUser(username, email, password)) {
+                Server.sendResponse(exchange, 200, "{\"message\": \"Registration successful!\"}");
+            } else {
+                Server.sendResponse(exchange, 400, "{\"message\": \"Registration failed! User may already exist.\"}");
+            }
+        } catch (SQLException e) {
+            e.printStackTrace();
+            Server.sendResponse(exchange, 500, "{\"message\": \"Internal server error\"}");
+        }
+    }
+
+    private void handleLogin(HttpExchange exchange) throws IOException {
+        String requestBody = new String(exchange.getRequestBody().readAllBytes());
+        ObjectMapper mapper = new ObjectMapper();
+        Map<String, String> formData = mapper.readValue(requestBody, Map.class);
+
+        if (formData.containsKey("id_token")) {
+            handleGoogleSignIn(exchange, formData.get("id_token"));
+        } else {
+            handleFormLogin(exchange, formData.get("email"), formData.get("password"));
+        }
+    }
+
+    private void handleGoogleSignIn(HttpExchange exchange, String idTokenString) throws IOException {
+        HttpTransport transport = new NetHttpTransport();
+        JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
+
+        GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
+                .setAudience(Collections.singletonList(CLIENT_ID)).build();
+
+        try {
+            GoogleIdToken idToken = verifier.verify(idTokenString);
+            if (idToken != null) {
+                GoogleIdToken.Payload payload = idToken.getPayload();
+                String email = payload.getEmail();
+                if (DatabaseUtil.userExists(email)) {
+                    System.out.println("User exists, logging in");
+                    handleFormLogin(exchange, email, null);
+                } else {
+                    System.out.println("User does not exist, creating new user");
+                    String name = (String) payload.get("name");
+                    DatabaseUtil.registerUser(name, email, null); // Password is null for Google login
+                    String response = createSession(email);
+                    Server.sendResponse(exchange, 200, response);
+                }
+            } else {
+                String response = "{\"message\": \"Invalid ID token\"}";
+                System.out.println(response);
+                Server.sendResponse(exchange, 401, response);
+            }
+        } catch (SQLException e) {
+            e.printStackTrace();
+            String response = "{\"message\": \"Database error\"}";
+            System.out.println(response);
+            Server.sendResponse(exchange, 500, response);
+        } catch (GeneralSecurityException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private void handleFormLogin(HttpExchange exchange, String email, String password) throws IOException {
+        try {
+            if (DatabaseUtil.userExists(email)) {
+                if (DatabaseUtil.authenticateUser(email, password)) {
+                    String response = createSession(email);
+                    Server.sendResponse(exchange, 200, response);
+                } else {
+                    String response = "{\"message\": \"Invalid password\"}";
+                    System.out.println(response);
+                    Server.sendResponse(exchange, 401, response);
+                }
+            } else {
+                String response = "{\"message\": \"User does not exist\"}";
+                System.out.println(response);
+                Server.sendResponse(exchange, 404, response);
+            }
+        } catch (SQLException e) {
+            e.printStackTrace();
+            String response = "{\"message\": \"Database error: " + e.getMessage() + "\"}";
+            System.out.println(response);
+            Server.sendResponse(exchange, 500, response);
+        }
+    }
+
+    private void handleLogout(HttpExchange exchange) throws IOException {
+        String sessionId = getSessionId(exchange);
+        if (sessionId != null && sessions.containsKey(sessionId)) {
+            sessions.remove(sessionId);
+            Server.sendResponse(exchange, 200, "{\"message\": \"Logout successful\"}");
+        } else {
+            Server.sendResponse(exchange, 401, "{\"message\": \"Not logged in\"}");
+        }
+    }
+
+    private void handleDeleteAccount(HttpExchange exchange) throws IOException {
+        String userIdStr = new String(exchange.getRequestBody().readAllBytes()).replaceAll("\"", "");
+        int userId = Integer.parseInt(userIdStr);
+        Map<String, Object> response = new HashMap<>();
+        try {
+            boolean success = DatabaseUtil.deleteUser(userId);
+            response.put("success", success);
+            if (!success) {
+                response.put("message", "User not found");
+            }
+        } catch (SQLException e) {
+            e.printStackTrace();
+            response.put("success", false);
+            response.put("message", "Database error: " + e.getMessage());
+        }
+
+        String jsonResponse = new ObjectMapper().writeValueAsString(response);
+        Server.sendResponse(exchange, 200, jsonResponse);
+    }
+
+
+    private String createSession(String email) throws SQLException {
+        String sessionId = UUID.randomUUID().toString();
+        sessions.put(sessionId, email);
+        boolean isAdmin = DatabaseUtil.isAdmin(email);
+        return "{\"message\": \"" + email + " logged in!\", \"sessionId\": \"" + sessionId + "\", \"isAdmin\": " + isAdmin + "}";
+    }
+
+}
Index: backend/GlobeGuru-backend/src/main/java/DatabaseUtil.java
===================================================================
--- backend/GlobeGuru-backend/src/main/java/DatabaseUtil.java	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ backend/GlobeGuru-backend/src/main/java/DatabaseUtil.java	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,345 @@
+import java.io.IOException;
+import java.sql.*;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+
+public class DatabaseUtil {
+
+    private static final String DB_URL = "jdbc:sqlite:globe_guru.db";
+
+    public static Connection getConnection() throws SQLException {
+        return DriverManager.getConnection(DB_URL);
+    }
+    public static void initializeDatabase() throws SQLException {
+        try (Connection conn = getConnection();
+             PreparedStatement stmt1 = conn.prepareStatement(
+                     "CREATE TABLE IF NOT EXISTS users (" +
+                             "id INTEGER PRIMARY KEY AUTOINCREMENT, " +
+                             "username TEXT NOT NULL UNIQUE, " +
+                             "email TEXT NOT NULL UNIQUE, " +
+                             "password TEXT, " +
+                             "isAdmin BOOLEAN NOT NULL DEFAULT FALSE)"
+             );
+             PreparedStatement stmt2 = conn.prepareStatement(
+                     "CREATE TABLE IF NOT EXISTS options (" +
+                             "id INTEGER PRIMARY KEY AUTOINCREMENT, " +
+                             "link TEXT, " +
+                             "imgSrc TEXT, " +
+                             "hotelName TEXT, " +
+                             "country TEXT, " +
+                             "price REAL, " +
+                             "dateRange TEXT, " +
+                             "isPriceChanged BOOLEAN DEFAULT 0, " +
+                             "newPrice REAL DEFAULT 0)"
+             );
+
+             PreparedStatement stmt3 = conn.prepareStatement(
+                     "CREATE TABLE IF NOT EXISTS savedOptions (" +
+                             "userId INTEGER, " +
+                             "optionId INTEGER, " +
+                             "FOREIGN KEY(userId) REFERENCES users(id), " +
+                             "FOREIGN KEY(optionId) REFERENCES options(id), " +
+                             "UNIQUE(userId, optionId))"
+             )) {
+            stmt1.executeUpdate();
+            stmt2.executeUpdate();
+            stmt3.executeUpdate();
+        }
+    }
+
+    public static boolean registerUser(String username, String email, String password) throws SQLException {
+        String sql = "INSERT INTO users (username, email, password) VALUES (?, ?, ?)";
+        try (Connection conn = getConnection();
+             PreparedStatement stmt = conn.prepareStatement(sql)) {
+            stmt.setString(1, username);
+            stmt.setString(2, email);
+            stmt.setString(3, password); // Store hashed
+            return stmt.executeUpdate() > 0;
+        }
+    }
+
+    public static boolean authenticateUser(String email, String password) throws SQLException {
+        String sql = "SELECT password FROM users WHERE email = ?";
+        try (Connection conn = getConnection();
+             PreparedStatement stmt = conn.prepareStatement(sql)) {
+            stmt.setString(1, email);
+            try (ResultSet rs = stmt.executeQuery()) {
+                if (rs.next()) {
+                    String storedPassword = rs.getString("password");
+                    if (password == null) {
+                        // Assume this is a Google login
+                        return storedPassword == null;
+                    }
+                    return password.equals(storedPassword); // Check hashed password
+                }
+            }
+        }
+        return false;
+    }
+
+    public static boolean deleteUser(int userId) throws SQLException {
+        String selectSql = "SELECT userId FROM users WHERE userId = ?";
+        String deleteSql = "DELETE FROM users WHERE userId = ?";
+        String deleteFavoritesSql = "DELETE FROM savedOptions WHERE userId = ?";
+
+        try (Connection conn = getConnection();
+             PreparedStatement selectStmt = conn.prepareStatement(selectSql);
+             PreparedStatement deleteStmt = conn.prepareStatement(deleteSql);
+             PreparedStatement deleteFavoritesStmt = conn.prepareStatement(deleteFavoritesSql)) {
+
+            selectStmt.setInt(1, userId);
+            try (ResultSet rs = selectStmt.executeQuery()) {
+                if (rs.next()) {
+                    // User exists, delete the user and their favourite options
+                    deleteStmt.setInt(1, userId);
+                    int rowsAffected = deleteStmt.executeUpdate();
+
+                    deleteFavoritesStmt.setInt(1, userId);
+                    deleteFavoritesStmt.executeUpdate();
+
+                    return rowsAffected > 0;
+                } else {
+                    // User does not exist
+                    return false;
+                }
+            }
+        }
+    }
+
+    public static boolean userExists(String email) throws SQLException {
+        String query = "SELECT COUNT(*) FROM users WHERE email = ?";
+        try (Connection connection = getConnection();
+             PreparedStatement statement = connection.prepareStatement(query)) {
+            statement.setString(1, email);
+            ResultSet resultSet = statement.executeQuery();
+            if (resultSet.next()) {
+                return resultSet.getInt(1) > 0;
+            }
+        }
+        return false;
+    }
+
+    public static boolean isAdmin(String email) throws SQLException {
+        String selectSql = "SELECT isAdmin FROM users WHERE email = ?";
+        try (Connection conn = getConnection();
+             PreparedStatement stmt = conn.prepareStatement(selectSql)) {
+            stmt.setString(1, email);
+            try (ResultSet rs = stmt.executeQuery()) {
+                if (rs.next()) {
+                    return rs.getBoolean("isAdmin");
+                }
+            }
+        }
+        return false;
+    }
+
+    public static List<Option> queryOptions(String destination, String dateQuery, boolean dateFlag) throws SQLException {
+        List<Option> options = new ArrayList<>();
+        String sql = "SELECT * FROM options WHERE (country LIKE ? OR hotelName LIKE ?)";
+        System.out.println(dateQuery);
+        if (dateQuery != null && !dateQuery.isEmpty() && !dateFlag) {
+            sql += (" AND dateRange = ?");
+        } //append date
+        if (dateFlag) {   //search only from dates
+            sql += "AND dateRange LIKE ?";
+        }
+        System.out.println("Searching for dest:" + destination + "\n" + sql);
+        try (Connection conn = getConnection();
+             PreparedStatement stmt = conn.prepareStatement(sql)) {
+            stmt.setString(1, "%" + destination + "%");
+            stmt.setString(2, "%" + destination + "%");
+            if (dateQuery != null && !dateQuery.isEmpty() && !dateFlag) {
+                stmt.setString(3, dateQuery);
+            }
+            if (dateFlag) {
+                stmt.setString(3, dateQuery + "%");
+            }
+            // Execute query
+            try (ResultSet rs = stmt.executeQuery()) {
+                while (rs.next()) {
+                    Option option = new Option();
+                    option.setId(rs.getInt("id"));
+                    option.setLink(rs.getString("link"));
+                    option.setImgSrc(rs.getString("imgSrc"));
+                    option.setHotelName(rs.getString("hotelName"));
+                    option.setCountry(rs.getString("country"));
+                    option.setPrice(rs.getFloat("price"));
+                    option.setDateRange(rs.getString("dateRange"));
+                    options.add(option);
+                }
+            }
+        }
+        System.out.println("Found " + options.size());
+        return options;
+    }
+
+    public static boolean saveFavoriteOption(int userId, int optionId) throws SQLException {
+        String sql = "INSERT INTO savedOptions (userId, optionId) VALUES (?, ?) ON CONFLICT DO NOTHING";
+        try (Connection conn = getConnection();
+             PreparedStatement stmt = conn.prepareStatement(sql)) {
+            stmt.setInt(1, userId);
+            stmt.setInt(2, optionId);
+            return stmt.executeUpdate() > 0;
+        }
+    }
+
+    //TODO add frontend
+    public static boolean removeFavoriteOption(int userId, int optionId) throws SQLException {
+        String sql = "DELETE FROM savedOptions WHERE userId = ? AND optionId = ?";
+        try (Connection conn = getConnection(); PreparedStatement stmt = conn.prepareStatement(sql)) {
+            stmt.setInt(1, userId);
+            stmt.setInt(2, optionId);
+            return stmt.executeUpdate() > 0;
+        }
+    }
+
+    public static List<Option> getSavedTripsByUser(int userId) throws SQLException {
+        List<Option> savedTrips = new ArrayList<>();
+        String sql = "SELECT options.* FROM savedOptions JOIN options ON savedOptions.optionId = options.id WHERE savedOptions.userId = ?";
+        try (Connection conn = getConnection();
+             PreparedStatement stmt = conn.prepareStatement(sql)) {
+            stmt.setInt(1, userId);
+            try (ResultSet rs = stmt.executeQuery()) {
+                while (rs.next()) {
+                    Option option = new Option();
+                    option.setId(rs.getInt("id"));
+                    option.setLink(rs.getString("link"));
+                    option.setImgSrc(rs.getString("imgSrc"));
+                    option.setHotelName(rs.getString("hotelName"));
+                    option.setCountry(rs.getString("country"));
+                    option.setPrice(rs.getFloat("price"));
+                    option.setDateRange(rs.getString("dateRange"));
+                    option.setPriceChanged(rs.getBoolean("isPriceChanged"));
+                    option.setNewPrice(rs.getInt("newPrice"));
+                    savedTrips.add(option);
+                }
+            }
+        }
+        return savedTrips;
+    }
+
+
+    public static int getUserIdByEmail(String email) throws SQLException {
+        String sql = "SELECT id FROM users WHERE email = ?";
+        try (Connection conn = getConnection();
+             PreparedStatement stmt = conn.prepareStatement(sql)) {
+            stmt.setString(1, email);
+            try (ResultSet rs = stmt.executeQuery()) {
+                if (rs.next()) {
+                    return rs.getInt("id");
+                } else {
+                    throw new SQLException("User not found");
+                }
+            }
+        }
+    }
+
+    public static int getCurrentOptionsCount() throws SQLException {
+        String sql = "SELECT COUNT(*) AS optionsCount FROM options";
+        try (Connection conn = getConnection();
+             PreparedStatement stmt = conn.prepareStatement(sql);
+             ResultSet rs = stmt.executeQuery()) {
+            if (rs.next()) {
+                return rs.getInt("optionsCount");
+            } else {
+                return 0;
+            }
+        }
+    }
+
+    public static int getChangedOptionsCountSinceLastUpdate() throws SQLException, IOException {
+        LocalDateTime lastUpdateTime = Server.getLastUpdateTime();
+        if (lastUpdateTime == null) {
+            return 0;
+        }
+        String sql = "SELECT COUNT(*) AS changedOptionsCount FROM options WHERE lastModified > ?";
+        try (Connection conn = getConnection();
+             PreparedStatement stmt = conn.prepareStatement(sql)) {
+            stmt.setTimestamp(1, Timestamp.valueOf(lastUpdateTime));
+            try (ResultSet rs = stmt.executeQuery()) {
+                if (rs.next()) {
+                    return rs.getInt("changedOptionsCount");
+                } else {
+                    return 0;
+                }
+            }
+        }
+    }
+
+    public static void saveOptionToDatabase(Option option) {
+        String sql = "INSERT INTO options (link, imgSrc, hotelName, country, price, dateRange, isPriceChanged, newPrice) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
+        try (Connection conn = DriverManager.getConnection("jdbc:sqlite:globe_guru.db");
+             PreparedStatement stmt = conn.prepareStatement(sql)) {
+            stmt.setString(1, option.getLink());
+            stmt.setString(2, option.getImgSrc());
+            stmt.setString(3, option.getHotelName());
+            stmt.setString(4, option.getCountry());
+            stmt.setFloat(5, option.getPrice());
+            stmt.setString(6, option.getDateRange());
+            stmt.setBoolean(7, option.isPriceChanged());
+            stmt.setFloat(8, option.getNewPrice());
+            stmt.executeUpdate();
+        } catch (SQLException e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    public static void dropOptions() throws SQLException {
+        String sql = "DROP TABLE options";
+        try (
+            Connection conn = getConnection();
+            PreparedStatement stmt = conn.prepareStatement(sql)){
+            stmt.executeUpdate();
+            //Remake the options DB
+            initializeDatabase();
+
+        }
+    }
+    public static void updateOptionInDatabase(Option option) {
+        String sql = "UPDATE options SET link = ?, imgSrc = ?, hotelName = ?, country = ?, price = ?, dateRange = ?, isPriceChanged = ?, newPrice = ? WHERE id = ?";
+        try (Connection conn = DriverManager.getConnection("jdbc:sqlite:globe_guru.db");
+             PreparedStatement stmt = conn.prepareStatement(sql)) {
+            stmt.setString(1, option.getLink());
+            stmt.setString(2, option.getImgSrc());
+            stmt.setString(3, option.getHotelName());
+            stmt.setString(4, option.getCountry());
+            stmt.setFloat(5, option.getPrice());
+            stmt.setString(6, option.getDateRange());
+            stmt.setBoolean(7, option.isPriceChanged());
+            stmt.setFloat(8, option.getNewPrice());
+            stmt.setInt(9, option.getId());
+            stmt.executeUpdate();
+        } catch (SQLException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static Option findOption(Option option) {
+        String sql = "SELECT * FROM options WHERE id = ?";
+        try (Connection conn = DriverManager.getConnection("jdbc:sqlite:globe_guru.db");
+             PreparedStatement stmt = conn.prepareStatement(sql)) {
+            stmt.setInt(1, option.getId());
+            try (ResultSet rs = stmt.executeQuery()) {
+                if (rs.next()) {
+                    Option existingOption = new Option();
+                    existingOption.setId(rs.getInt("id"));
+                    existingOption.setLink(rs.getString("link"));
+                    existingOption.setImgSrc(rs.getString("imgSrc"));
+                    existingOption.setHotelName(rs.getString("hotelName"));
+                    existingOption.setCountry(rs.getString("country"));
+                    existingOption.setPrice(rs.getFloat("price"));
+                    existingOption.setDateRange(rs.getString("dateRange"));
+                    existingOption.setPriceChanged(rs.getBoolean("isPriceChanged"));
+                    existingOption.setNewPrice(rs.getInt("newPrice"));
+                    return existingOption;
+                }
+            }
+        } catch (SQLException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+}
Index: backend/GlobeGuru-backend/src/main/java/FrontendHandler.java
===================================================================
--- backend/GlobeGuru-backend/src/main/java/FrontendHandler.java	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ backend/GlobeGuru-backend/src/main/java/FrontendHandler.java	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,165 @@
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpExchange;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.sql.SQLException;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.io.File;
+
+public class FrontendHandler implements HttpHandler {
+    private static final ExecutorService executorService = Executors.newFixedThreadPool(1);
+
+    @Override
+    public void handle(HttpExchange exchange) throws IOException {
+        String uri = exchange.getRequestURI().toString();
+        String path = exchange.getRequestURI().getPath();
+        String method = exchange.getRequestMethod();
+
+        if ("GET".equalsIgnoreCase(method)) {
+            handleGetRequests(exchange, path, uri);
+        } else if ("POST".equalsIgnoreCase(method)) {
+            handlePostRequests(exchange, path);
+        } else {
+            Server.sendResponse(exchange, 405, "{\"message\": \"Method not allowed.\"}");
+        }
+    }
+
+    private void handleGetRequests(HttpExchange exchange, String path, String uri) throws IOException {
+        switch (path) {
+            case "/admin/last-update-time":
+                String lastUpdateTimeResponse = "{\"lastUpdateTime\": \"" + Server.getLastUpdateTime().toString() + "\"}";
+                Server.sendResponse(exchange, 200, lastUpdateTimeResponse);
+                break;
+            case "/admin/current-options-count":
+                int currentOptionsCount;
+                try {
+                    currentOptionsCount = DatabaseUtil.getCurrentOptionsCount();
+                } catch (SQLException e) {
+                    throw new RuntimeException(e);
+                }
+                String currentOptionsCountResponse = "{\"currentOptionsCount\": " + currentOptionsCount + "}";
+                Server.sendResponse(exchange, 200, currentOptionsCountResponse);
+                break;
+            case "/admin/changed-options-count":
+                int changedOptionsCount;
+                try {
+                    changedOptionsCount = DatabaseUtil.getChangedOptionsCountSinceLastUpdate();
+                } catch (SQLException e) {
+                    throw new RuntimeException(e);
+                }
+                String changedOptionsCountResponse = "{\"changedOptionsCount\": " + changedOptionsCount + "}";
+                Server.sendResponse(exchange, 200, changedOptionsCountResponse);
+                break;
+            case"/admin/drop-db":
+                try {
+                    System.out.println("DROPPING DATABASE!");
+                    DatabaseUtil.dropOptions();
+                } catch (SQLException e) {
+                    throw new RuntimeException(e);
+                }
+                break;
+            default:
+                serveStaticFiles(exchange, uri);
+                break;
+        }
+    }
+
+    private void handlePostRequests(HttpExchange exchange, String path) throws IOException {
+        if (path.equalsIgnoreCase("/admin/start-scraper")) {
+            Future<Void> future = executorService.submit(new Scraper());
+            Server.updateLastUpdateTime();
+            Server.sendResponse(exchange, 200, "{\"message\": \"Starting options update.\"}");
+            executorService.submit(() -> {
+                try {
+                    future.get();
+                } catch (Exception e) {
+                    e.printStackTrace();
+
+                }
+            });
+        } else if (path.equalsIgnoreCase("/submit")) {
+            handleFormSubmit(exchange);
+        }else {
+            Server.sendResponse(exchange, 404, "{\"message\": \"Endpoint not found.\"}");
+        }
+    }
+
+    private void handleFormSubmit(HttpExchange exchange) throws IOException {
+        String requestBody = new String(exchange.getRequestBody().readAllBytes());
+        System.out.println("Form data: " + requestBody);
+        ObjectMapper mapper = new ObjectMapper();
+        Map<String, String> formData = mapper.readValue(requestBody, Map.class);
+        String destination = formData.get("destination");
+        String departureDate = formData.get("departureDate");
+        String nightsNumberStr = formData.get("nightsNumber");
+        int numberOfNights = (nightsNumberStr != null && !nightsNumberStr.isEmpty()) ? Integer.parseInt(nightsNumberStr) : 0;
+        String queryDate = "";
+        boolean dateFlag = false;
+
+        if (departureDate != null && !departureDate.isEmpty()) {
+            if (numberOfNights != 0) {
+                queryDate = LocalDate.parse(departureDate, DateTimeFormatter.ofPattern("yyyy-MM-dd"))
+                        .format(DateTimeFormatter.ofPattern("dd.MM.yyyy"));
+                String dateTo = LocalDate.parse(departureDate, DateTimeFormatter.ofPattern("yyyy-MM-dd"))
+                        .plusDays(numberOfNights).format(DateTimeFormatter.ofPattern("dd.MM.yyyy"));
+                queryDate += " - " + dateTo;
+            } else {
+                dateFlag = true; // send only from date
+                queryDate = LocalDate.parse(departureDate, DateTimeFormatter.ofPattern("yyyy-MM-dd"))
+                        .format(DateTimeFormatter.ofPattern("dd.MM.yyyy"));
+            }
+        }
+
+        List<Option> options;
+        try {
+            options = DatabaseUtil.queryOptions(destination, queryDate, dateFlag);
+        } catch (SQLException e) {
+            e.printStackTrace();
+            exchange.sendResponseHeaders(500, -1);
+            exchange.close();
+            return;
+        }
+
+        Server.sendResponse(exchange, 200, mapper.writeValueAsString(options));
+    }
+
+    private void serveStaticFiles(HttpExchange exchange, String uri) throws IOException {
+        File file;
+        String contentType = "text/html";
+
+        if (uri.equals("/admin-panel")) {
+            System.out.println("Serving admin panel");
+            file = new File(System.getProperty("user.dir") + "/frontend/admin-panel.html");
+        } else {
+            file = new File(System.getProperty("user.dir") + "/frontend" + uri);
+            if (uri.endsWith(".css")) {
+                contentType = "text/css";
+            } else if (uri.endsWith(".js")) {
+                contentType = "application/javascript";
+            }
+        }
+
+        if (!file.exists() || !file.isFile()) {
+            file = new File("frontend/index.html");
+        }
+
+        if (file.exists() && file.isFile()) {
+            exchange.getResponseHeaders().set("Content-Type", contentType);
+            exchange.sendResponseHeaders(200, file.length());
+            OutputStream outputStream = exchange.getResponseBody();
+            Files.copy(file.toPath(), outputStream);
+            outputStream.close();
+        } else {
+            exchange.sendResponseHeaders(404, -1);
+        }
+    }
+
+}
Index: backend/GlobeGuru-backend/src/main/java/Option.java
===================================================================
--- backend/GlobeGuru-backend/src/main/java/Option.java	(revision d4d8f6155e80421fe9fc8c1ee34e0b784226b96c)
+++ backend/GlobeGuru-backend/src/main/java/Option.java	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -1,15 +1,32 @@
+import java.util.Objects;
+
 public class Option {
+    private int id;
     private String hotelName;
     private String country;
-    private String price;
-    private String link; // Ensure to add a field for link
+    private float price;
+    private String link;
     private String imgSrc;
+
+    //Price changing
+    private float newPrice = 0;
+    private boolean isPriceChanged = false;
+    private String dateRange;
     // Constructor
-    public Option(){}
+    public Option(){
+        price = 0;
+    }
+
+    public void setDateRange(String dateRange) {
+        this.dateRange = dateRange;
+    }
+
+    public String getDateRange() {
+        return dateRange;
+    }
 
     public boolean isEmpty(){
-        return (hotelName == null || country == null || price == null || link == null || imgSrc == null);
+        return (hotelName == null || country == null || price == 0 || link == null || imgSrc == null);
     }
-    // Getters and setters (ensure you have these methods)
     public String getHotelName() {
         return hotelName;
@@ -28,9 +45,9 @@
     }
 
-    public String getPrice() {
+    public float getPrice() {
         return price;
     }
 
-    public void setPrice(String price) {
+    public void setPrice(float price) {
         this.price = price;
     }
@@ -52,13 +69,55 @@
     }
 
-    // toString method (for debugging purposes)
+    @Override
+    public boolean equals(Object obj) {
+        if(this==obj) return true;
+        if(obj == null || getClass() != obj.getClass()) return false;
+        Option option = (Option) obj;
+        return Float.compare(option.price, price) == 0
+                && Objects.equals(hotelName, option.hotelName)
+                && Objects.equals(country, option.country)
+                && Objects.equals(link, option.link);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(hotelName,country,price,link);
+    }
+
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    //debug
     @Override
     public String toString() {
         return "Option{" +
+                "id='" + id + '\'' +
+                "dateRange='" + dateRange + '\'' +
                 "hotelName='" + hotelName + '\'' +
                 ", country='" + country + '\'' +
                 ", price='" + price + '\'' +
                 ", link='" + link + '\'' +
+                ", image='" + imgSrc +
                 '}';
     }
+
+    public void setPriceChanged(boolean a){
+        isPriceChanged = a;
+    }
+    public void setNewPrice(float a){
+        newPrice = a;
+    }
+
+    public boolean isPriceChanged() {
+        return isPriceChanged;
+    }
+
+    public float getNewPrice() {
+        return newPrice;
+    }
 }
Index: backend/GlobeGuru-backend/src/main/java/Scraper.java
===================================================================
--- backend/GlobeGuru-backend/src/main/java/Scraper.java	(revision d4d8f6155e80421fe9fc8c1ee34e0b784226b96c)
+++ backend/GlobeGuru-backend/src/main/java/Scraper.java	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -7,21 +7,22 @@
 import java.util.Iterator;
 import java.util.List;
+import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.CountDownLatch;
 
-public class Scraper extends Thread {
+public class Scraper implements Callable<Void> {
+
     private List<String> urls;
-    private String destination;
-    private String departureDate;
-    private int numberOfPeople;
     private ConcurrentLinkedQueue<Option> optionsQueue;
     private CountDownLatch latch;
 
-    public Scraper(String destination, String departureDate, int numberOfPeople) {
+    public Scraper() {
         urls = new ArrayList<>();
         this.optionsQueue = new ConcurrentLinkedQueue<>();
         ObjectMapper mapper = new ObjectMapper();
         try {
-            JsonNode root = mapper.readTree(new File("src/main/java/URLsJSON.json"));
+            ClassLoader classLoader = getClass().getClassLoader();
+            JsonNode root = mapper.readTree(new File(classLoader.getResource("URLsJSON.json").getFile()));
+
             JsonNode urlNode = root.get("agencyurls");
             if (urlNode.isArray()) {
@@ -36,24 +37,14 @@
             throw new RuntimeException(e);
         }
-        this.destination = destination;
-        this.departureDate = departureDate;
-        this.numberOfPeople = numberOfPeople;
         this.latch = new CountDownLatch(urls.size());
     }
 
-    @Override
-    public void run() {
+
+    public Void call() {
         System.out.println("Scraper has started ");
         for (String url : urls) {
-            new ScraperThread(url, destination, departureDate, numberOfPeople, optionsQueue, latch).start();
+            new ScraperThread(url, optionsQueue, latch).start();
         }
-    }
-    public List<Option> getOptions() {
-        try {
-            latch.await();  // Wait for all threads to finish
-        } catch (InterruptedException e) {
-            e.printStackTrace();
-        }
-        return new ArrayList<>(optionsQueue);
+        return null;
     }
 }
Index: ckend/GlobeGuru-backend/src/main/java/ScraperServer.java
===================================================================
--- backend/GlobeGuru-backend/src/main/java/ScraperServer.java	(revision d4d8f6155e80421fe9fc8c1ee34e0b784226b96c)
+++ 	(revision )
@@ -1,85 +1,0 @@
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.sun.net.httpserver.HttpExchange;
-import com.sun.net.httpserver.HttpHandler;
-import com.sun.net.httpserver.HttpServer;
-import org.openqa.selenium.internal.Debug;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.net.InetSocketAddress;
-import java.nio.file.Files;
-import java.util.List;
-import java.util.Map;
-
-public class ScraperServer {
-
-    public static void main(String[] args) throws IOException {
-        // Start HTTP server
-        HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
-        server.createContext("/", new FrontendHandler());
-        server.createContext("/submit", new FormHandler());
-        server.start();
-
-        System.out.println("Server started on port 8000");
-    }
-
-    static class FrontendHandler implements HttpHandler {
-        public void handle(HttpExchange exchange) throws IOException {
-            String uri = exchange.getRequestURI().toString();
-            File file = new File("frontend" + uri);
-            if (!file.exists() || !file.isFile()) {
-                file = new File("frontend/index.html"); // Default to index.html
-            }
-
-            exchange.sendResponseHeaders(200, file.length());
-            OutputStream outputStream = exchange.getResponseBody();
-            Files.copy(file.toPath(), outputStream);
-            outputStream.close();
-        }
-    }
-
-    static class FormHandler implements HttpHandler {
-        @Override
-        public void handle(HttpExchange exchange) throws IOException {
-            if (exchange.getRequestMethod().equalsIgnoreCase("POST")) {
-                // Read form data from request body
-                String requestBody = new String(exchange.getRequestBody().readAllBytes());
-                System.out.println("Form data: " + requestBody);
-
-                ObjectMapper mapper = new ObjectMapper();
-                Map<String, String> formData = mapper.readValue(requestBody, Map.class);
-                String destination = formData.get("destination");
-                String departureDate = formData.get("departureDate");
-                int numberOfPeople = Integer.parseInt(formData.get("numberOfPeople"));
-
-                // Start Scraper thread with form data
-                Scraper scraper = new Scraper(destination, departureDate, numberOfPeople);
-                scraper.start();
-
-                // Wait for the scraper threads to finish
-                try {
-                    scraper.join(); // Ensure the scraper thread completes
-                } catch (InterruptedException e) {
-                    e.printStackTrace();
-                }
-
-                List<Option> options = scraper.getOptions();
-                //System.out.println("Scraper finished with options: " + options);
-
-                // Respond with JSON data
-                String optionsJson = mapper.writeValueAsString(options);
-                exchange.getResponseHeaders().set("Content-Type", "application/json");
-                exchange.sendResponseHeaders(200, optionsJson.getBytes().length);
-                OutputStream outputStream = exchange.getResponseBody();
-                outputStream.write(optionsJson.getBytes());
-                outputStream.close();
-            } else {
-                // Method not allowed
-                exchange.sendResponseHeaders(405, -1);
-                exchange.close();
-            }
-        }
-    }
-
-}
Index: backend/GlobeGuru-backend/src/main/java/ScraperThread.java
===================================================================
--- backend/GlobeGuru-backend/src/main/java/ScraperThread.java	(revision d4d8f6155e80421fe9fc8c1ee34e0b784226b96c)
+++ backend/GlobeGuru-backend/src/main/java/ScraperThread.java	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -1,3 +1,7 @@
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.openqa.selenium.By;
 import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
 import org.openqa.selenium.chrome.ChromeDriver;
 import org.openqa.selenium.chrome.ChromeOptions;
@@ -6,5 +10,17 @@
 import org.jsoup.nodes.Element;
 import org.jsoup.select.Elements;
-
+import org.openqa.selenium.support.ui.ExpectedCondition;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import java.io.File;
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.*;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.CountDownLatch;
@@ -12,106 +28,143 @@
 public class ScraperThread extends Thread {
     private String url;
-    private String destination;
-    private String departureDate;
-    private int numberOfPeople;
     private ConcurrentLinkedQueue<Option> uniqueOptions;
     private CountDownLatch latch;
-
-    public ScraperThread(String url, String destination, String departureDate, int numberOfPeople, ConcurrentLinkedQueue<Option> optionsQueue, CountDownLatch latch) {
+    private Set<Option> optionSet;
+
+    public ScraperThread(String url, ConcurrentLinkedQueue<Option> optionsQueue, CountDownLatch latch) {
         this.url = url;
-        this.destination = destination;
-        this.departureDate = departureDate;
-        this.numberOfPeople = numberOfPeople;
         this.uniqueOptions = optionsQueue;
         this.latch = latch;
+        this.optionSet = new HashSet<>();
+    }
+
+    private WebDriver driver;
+
+    private void initializeWebDriver() {
+        System.setProperty("webdriver.chrome.driver", "C:\\chromedriver-win64\\chromedriver.exe");
+        ChromeOptions options = new ChromeOptions();
+        options.setBinary("C:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe");
+        options.addArguments("--headless");
+        options.addArguments("--disable-gpu");
+        options.addArguments("--remote-allow-origins=*");
+        options.addArguments("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");
+        driver = new ChromeDriver(options);
+    }
+
+    private void closeWebDriver() {
+        if (driver != null) {
+            driver.quit();
+        }
     }
 
     private void connectToWeb(String queryUrl) {
-        // Selenium
-        ChromeOptions options = new ChromeOptions();
-        options.setBinary("C:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe"); // Path to Brave, remove for Chrome compatibility
-        options.addArguments("--headless");  // Run in headless mode
-        options.addArguments("--disable-gpu");
-        options.addArguments("--window-size=1920,1080");
-        options.addArguments("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"); // User-Agent
-
-        // chromeDriver
-        System.setProperty("webdriver.chrome.driver", "C:\\drivers\\chromedriver.exe");
-        System.setProperty("webdriver.http.factory", "jdk-http-client");
-        WebDriver driver = new ChromeDriver(options);
-        try {
-            // Navigate to URL
-            driver.get(queryUrl);
-            Thread.sleep(10000); // Sleep to fetch all data
-
-            // Get page source
-            String pageSource = driver.getPageSource();
-            System.out.println("Thread " + Thread.currentThread().getId() + " connected to " + queryUrl);
-
-            // Get only options
-            Document doc = Jsoup.parse(pageSource);
-            Element parentDiv;
-            Elements childDivs;
-            switch (url) {
-                case "https://www.fibula.com.mk/":
-                    parentDiv = doc.selectFirst("div.flex.flex-col.gap-5");
-                    if (parentDiv != null) {
-                        childDivs = parentDiv.select("div");
-                        for (Element div : childDivs) {
-                            String data = div.html();
-                            Option option = optionParser(data);
-                            if (option != null) {
-                                if (uniqueOptions.add(option)) {
-                                    System.out.println("Parsed Option: " + option);
+        driver.get(queryUrl);
+
+        WebDriverWait wait = new WebDriverWait(driver, 40); // 40s timeout buffer
+        switch (url) {
+            case "https://booking.escapetravel.mk/":
+                wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("#hotels-container")));
+                try { Thread.sleep(5000);} catch (InterruptedException e) { e.printStackTrace(); }
+                break;
+            case "https://magelantravel.mk/":
+                wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("div.sodrzina")));
+                break;
+            default:
+                System.out.println("URL not recognized for waiting condition.");
+                // Handle other URLs if needed
+        }
+
+        String pageSource = driver.getPageSource();
+        System.out.println("Connected to " + queryUrl);
+        Document doc = Jsoup.parse(pageSource);
+        Element parentDiv;
+        Elements childDivs;
+
+        switch (url) {
+            case "https://www.fibula.com.mk/":
+                parentDiv = doc.selectFirst("div.flex.flex-col.gap-5");
+                if (parentDiv != null) {
+                    childDivs = parentDiv.select("div");
+                    for (Element div : childDivs) {
+                        String data = div.html();
+                        Option option = optionParser(data);
+                        if (option != null && optionSet.add(option)) {
+                            uniqueOptions.add(option);
+                            System.out.println("Parsed " + option);
+                        }
+                    }
+                } else {
+                    System.out.println("Parent div not found");
+                }
+                break;
+            case "https://booking.escapetravel.mk/":
+                parentDiv = doc.selectFirst("#hotels-container");
+                if (parentDiv != null) {
+                    childDivs = parentDiv.select("a.hotel-item");
+                    for (Element div : childDivs) {
+                        String data = div.outerHtml();
+                        Option option = optionParser(data);
+                        if (option != null) {
+                            Option existingOption = DatabaseUtil.findOption(option);
+                            if (existingOption != null) {
+                                if (existingOption.equals(option) || existingOption.getPrice() != option.getPrice()) {
+                                    option.setPriceChanged(true);
+                                    option.setNewPrice(option.getPrice());
                                 }
+                                DatabaseUtil.updateOptionInDatabase(option);
+                            } else if (optionSet.add(option)) {
+                                uniqueOptions.add(option);
+                                DatabaseUtil.saveOptionToDatabase(option);
+                                System.out.println("Parsed " + option);
                             }
                         }
-                    } else {
-                        System.out.println("Parent div not found");
-                    }
-                    break;
-                case "https://booking.escapetravel.mk/":
-                    parentDiv = doc.selectFirst("div.container.pt-4.pt-md-6.scroll-into-view");
-                    Element subParent;
-                    System.out.println(parentDiv);
-                    if(parentDiv != null) {
-                         subParent = parentDiv.selectFirst("div.row");
-                    }else{
-                        System.out.println("Parent div not found");
-                        break;
-                    }
-
-                    if (subParent != null) {
-                        childDivs = subParent.select("div.col-md-3");
-
-                        for (Element div : childDivs) {
-                            String data = div.html();
-                            Option option = optionParser(data);
-                            if (option != null) {
-                                if (uniqueOptions.add(option)) {
-                                    System.out.println("Parsed option: " + option);
+                    }
+                } else {
+                    System.out.println("Parent div not found");
+                }
+                break;
+            case "https://magelantravel.mk/":
+                parentDiv = doc.selectFirst("div.sodrzina");
+                if (parentDiv != null) {
+                    childDivs = parentDiv.select("div.destinacija");
+                    System.out.println(childDivs.size());
+                    childDivs.removeIf(div -> div.attr("style").contains("display:none") || div.attr("style").contains("display: none"));
+                    System.out.println("Filtered childDivs size: " + childDivs.size());
+                    for (Element div : childDivs) {
+                        String data = div.outerHtml();
+                        Option newOption = optionParser(data);
+                        if (newOption != null) {
+                            Option existingOption = DatabaseUtil.findOption(newOption);
+                            if (existingOption != null) {
+                                if (existingOption.equals(newOption) || existingOption.getPrice() != newOption.getPrice()) {
+                                    newOption.setPriceChanged(true);
+                                    newOption.setNewPrice(newOption.getPrice());
                                 }
+                                DatabaseUtil.updateOptionInDatabase(newOption);
+                            } else if (optionSet.add(newOption)) {
+                                uniqueOptions.add(newOption);
+                                DatabaseUtil.saveOptionToDatabase(newOption);
+                                System.out.println("Parsed " + newOption);
                             }
                         }
-                    }else {
-                        System.out.println("subparent div not found");
-                    }
-                    break;
-            }
-        } catch (InterruptedException e) {
-            e.printStackTrace();
-        } finally {
-            driver.quit();
-            latch.countDown();
-        }
-    }
+                    }
+
+        } else {
+                    System.out.println("Parent div not found");
+                }
+                break;
+            default:
+                System.out.println("URL not recognized for parsing.");
+        }
+    }
+
+
 
     private Option optionParser(String data) {
         Document doc = Jsoup.parse(data);
         Option created = new Option();
-
         switch (url) {
-            case "https://www.fibula.com.mk/":
-                created = parseFibula(doc);
+            case "https://magelantravel.mk/":
+                created = parseMagelan(doc);
                 break;
             case "https://booking.escapetravel.mk/":
@@ -122,92 +175,136 @@
                 break;
         }
-
         if (created.isEmpty()) {
+            System.out.println(created);
             return null;
         }
-
         return created;
     }
 
-    private Option parseFibula(Document doc) {
+    private Option parseMagelan(Document doc) {
         Option created = new Option();
-
-        Element linkElement = doc.selectFirst("a[target='_blank']");
-        created.setLink(linkElement != null ? url + linkElement.attr("href") : null);
-
-        Element imgElement = doc.selectFirst("div.md\\:aspect-none img");
-        created.setImgSrc(imgElement != null ? imgElement.attr("src") : null);
-
-        Element hotelNameElement = doc.selectFirst("h5.text-md");
+        Element linkElement = doc.selectFirst("div.ponuda-sredina");
+        int id = Integer.parseInt(linkElement.attr("data-id"));
+        int turop = Integer.parseInt(linkElement.attr("data-turop"));
+        created.setLink("https://magelantravel.mk/ponudi.php?type=1&objektid=" + id + "&turop=" + turop);
+        Element imgElement = doc.selectFirst("div.imgLiquidFill.imgLiquid.ponuda-img.zoom");
+        created.setImgSrc(imgElement != null ? url + imgElement.attr("style")
+                .split("url\\(")[1].split("\\)")[0].replace("'", "").replace("./", "/") : null);
+        Element hotelNameElement = doc.selectFirst("div.ponuda-objekt");
         created.setHotelName(hotelNameElement != null ? hotelNameElement.text() : null);
-
-        Element countryElement = doc.selectFirst("small.text-navy");
+        Element countryElement = doc.selectFirst("l.ponuda-lokacija");
         created.setCountry(countryElement != null ? countryElement.text() : null);
-
-        Element priceElement = doc.selectFirst("small.line-through");
-        String price = priceElement != null ? priceElement.text().replaceAll("[^\\d.]", "") : "0";
+        Element priceElement = doc.selectFirst("div.ponuda-cena");
+        Element dateElement = doc.selectFirst("l.ponuda-opis.termin");
+        created.setDateRange(dateElement != null ? dateElement.text() : null);
+        float price = Float.parseFloat(priceElement != null ? priceElement.text().replaceAll("[^\\d.]", "") : "0");
         created.setPrice(price);
-
         return created;
     }
-
     private Option parseEscapeTravel(Document doc) {
         Option created = new Option();
-
-        // Extract link
-        Element linkElement = doc.selectFirst("a[target='_blank']");
-        created.setLink(linkElement != null ? linkElement.attr("href") : null);
-
-        // Extract image source
-        Element imgElement = doc.selectFirst("img.card-img-top");
-        created.setImgSrc(imgElement != null ? imgElement.attr("src") : null);
-
-        // Extract hotel name
-        Element hotelNameElement = doc.selectFirst("h3.fw-bold.text-body.mb-2");
-        created.setHotelName(hotelNameElement != null ? hotelNameElement.text() : null);
-
-        // Extract country/location
-        Element countryElement = doc.selectFirst("h5.fw-light.text-primary.mb-1");
-        created.setCountry(countryElement != null ? countryElement.text() : null);
-
-        // Extract price
-        Element priceElement = doc.selectFirst("h4.fw-light.text-success.mb-0");
-        String price = priceElement != null ? priceElement.text().replaceAll("[^\\d.]", "") : "0";
+        Element card = doc.selectFirst("a.hotel-item");
+        String link = card.attr("href");
+        created.setLink(link);
+        created.setImgSrc(card.attr("data-picture"));
+        created.setHotelName(card.attr("data-title"));
+        Element countryP = doc.selectFirst("p.text-info");
+        created.setCountry(countryP != null ? countryP.text() : null);
+        Element priceElem = doc.selectFirst("span.hotel-price");
+        String priceText = priceElem.text();
+        float price = 0;
+        if(!priceText.isEmpty()) {
+            price = Float.parseFloat(priceText.replace("€", ""));
+        }
         created.setPrice(price);
-
+        String[] queryParams = link.split("[?&]");
+        String startDateStr = null;
+        int nights = 0;
+        for (String param : queryParams) {
+            if (param.startsWith("Date=")) {
+                startDateStr = param.split("=")[1];
+            }
+            if (param.startsWith("Nights=")) {
+                nights = Integer.parseInt(param.split("=")[1]);
+            }
+        }
+        if (startDateStr != null && nights > 0)
+        {
+            SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy");
+            try {
+                Date startDate = dateFormat.parse(startDateStr);
+
+                Calendar calendar = Calendar.getInstance();
+                calendar.setTime(startDate);
+                calendar.add(Calendar.DAY_OF_YEAR, nights);
+                Date endDate = calendar.getTime();
+                String dateRange = dateFormat.format(startDate) + " - " + dateFormat.format(endDate);
+                created.setDateRange(dateRange);
+            }catch (ParseException e){
+                e.printStackTrace();
+            }
+        }
         return created;
     }
 
-
     @Override
-        public void run() {
-            System.out.println("Thread started for url: " + url);
-            StringBuilder builder = new StringBuilder();
-            builder.append(url);
-            String queryUrl;
-            switch (url) {
-                case "https://www.fibula.com.mk/":
-                    builder.append("search?productType=2&"); // search for hotels
-                    for (int i = 0; i < numberOfPeople; i++) { // add all passengers (default adults)
-                        builder.append("passengers=1993-01-01&");
-                    }
-                    queryUrl = builder.toString();
-                    System.out.println(queryUrl);
-                    connectToWeb(queryUrl);
-                    break;
-                case "https://booking.escapetravel.mk/":
-                    builder.append("destinations?Category=&Search=&DateFrom=");
-                    builder.append(departureDate);
-                    builder.append("&Rooms=1&Adults=");
-                    builder.append(numberOfPeople);
-                    queryUrl = builder.toString();
-                    System.out.println(queryUrl);
-                    connectToWeb(queryUrl);
-                    break;
-                default:
-                    System.out.println("Not available for current url");
-                    latch.countDown();
-                    break;
-            }
-        }
-    }
+    public void run() {
+        System.out.println("Thread started for url: " + url);
+        initializeWebDriver();
+        if ("https://magelantravel.mk/".equals(url)) {
+            ObjectMapper mapper = new ObjectMapper();
+            try {
+                ClassLoader classLoader = getClass().getClassLoader();
+                JsonNode root = mapper.readTree(new File(classLoader.getResource("CountriesList.json").getFile()));
+                JsonNode countries = root.get("countries");
+                SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy");
+                Calendar calendar = Calendar.getInstance();
+                calendar.add(Calendar.DAY_OF_YEAR, 1);
+
+                for (int i = 0; i < 90; i++) { // next three months
+                    String date = dateFormat.format(calendar.getTime());
+                    for (JsonNode countryNode : countries) {
+                        String country = countryNode.asText();
+                        for (int nokevanja = 2; nokevanja <= 10; nokevanja++) {
+                            String queryUrl = url + "/destinacii?ah_tip=1&iframe=&affiliate_code=&carter_id=0&carter_region=&carter_dataod=&carter_datado=&destinacija=" + country + "&oddatum=" + date + "&nokevanja=" + nokevanja + "&dodatum=&broj_vozrasni=2&broj_deca=0&spdete1=0&spdete2=0&spdete3=0&spdete4=0";
+                            connectToWeb(queryUrl);
+                        }
+                    }
+                    calendar.add(Calendar.DAY_OF_YEAR, 1); // next day
+                }
+
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        } else if ("https://booking.escapetravel.mk/".equals(url)) {
+            ObjectMapper mapper = new ObjectMapper();
+            try {
+                ClassLoader classLoader = getClass().getClassLoader();
+                JsonNode root = mapper.readTree(new File(classLoader.getResource("CountriesList.json").getFile()));
+                JsonNode countries = root.get("countries"); // Assuming "destinations" key in JSON
+                SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy");
+                Calendar calendar = Calendar.getInstance();
+                calendar.add(Calendar.DAY_OF_YEAR, 1);
+
+                for (int i = 0; i < 90; i++) { // next three months
+                    String date = dateFormat.format(calendar.getTime());
+                    for (JsonNode countryNode : countries) {
+                        String country = countryNode.asText();
+                        for(int nokevanja = 2; nokevanja <=10; nokevanja ++) {
+                            String queryUrl = url + "/hotels?Search=" + country + "&Date=" + date + "&Nights=" + nokevanja + "&Rooms=1&Adults=2";
+                            connectToWeb(queryUrl);
+                        }
+                    }
+                    calendar.add(Calendar.DAY_OF_YEAR, 1); // next day
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        } else {
+            // Handle other URLs
+        }
+        closeWebDriver();
+        latch.countDown();
+    }
+
+}
Index: backend/GlobeGuru-backend/src/main/java/Server.java
===================================================================
--- backend/GlobeGuru-backend/src/main/java/Server.java	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ backend/GlobeGuru-backend/src/main/java/Server.java	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,193 @@
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
+import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
+import com.google.api.client.http.HttpTransport;
+import com.google.api.client.http.javanet.NetHttpTransport;
+import com.google.api.client.json.JsonFactory;
+import com.google.api.client.json.jackson2.JacksonFactory;
+
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.net.InetSocketAddress;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.GeneralSecurityException;
+import java.sql.SQLException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+public class Server {
+
+    public static void main(String[] args) throws IOException, SQLException {
+        // Start HTTP server
+        DatabaseUtil.initializeDatabase();
+        HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
+        server.createContext("/", new FrontendHandler());
+        server.createContext("/submit", new FrontendHandler());
+        server.createContext("/admin/start-scraper", new FrontendHandler());
+        server.createContext("/admin/last-update-time", new FrontendHandler());
+        server.createContext("/admin/current-options-count", new FrontendHandler());
+        server.createContext("/admin/changed-options-count", new FrontendHandler());
+
+        server.createContext("/account/login", new AccountHandler());
+        server.createContext("/account/register", new AccountHandler());
+        server.createContext("/account/delete-account", new AccountHandler());
+        server.createContext("/account/session", new AccountHandler());
+
+
+        server.createContext("/save-favorite", new SaveFavoriteHandler());
+        server.createContext("/get-saved-trips", new GetSavedTripsHandler());
+        server.createContext("/remove-from-saved", new RemoveFromSavedTripsHandler());
+
+        server.start();
+
+        System.out.println("Server started on port 8000");
+    }
+    static class RemoveFromSavedTripsHandler implements HttpHandler {
+        @Override
+        public void handle(HttpExchange exchange) throws IOException {
+            if (exchange.getRequestMethod().equalsIgnoreCase("POST")) {
+                String requestBody = new String(exchange.getRequestBody().readAllBytes());
+                ObjectMapper mapper = new ObjectMapper();
+                Map<String, Object> requestData = mapper.readValue(requestBody, Map.class);
+                String userEmail = (String) requestData.get("userEmail");
+                int optionId = (int) requestData.get("optionId");
+
+                int userId;
+                try {
+                    userId = DatabaseUtil.getUserIdByEmail(userEmail);
+                    boolean removed = DatabaseUtil.removeFavoriteOption(userId, optionId);
+                    if (removed) {
+                        sendResponse(exchange, 200, "{\"success\": true}");
+                    } else {
+                        sendResponse(exchange, 500, "{\"success\": false, \"message\": \"Failed to remove option\"}");
+                    }
+                } catch (SQLException e) {
+                    e.printStackTrace();
+                    sendResponse(exchange, 500, "{\"message\": \"Failed to retrieve user ID.\"}");
+                }
+            } else {
+                sendResponse(exchange, 405, "{\"message\": \"Method not allowed.\"}");
+            }
+        }
+    }
+    static class SaveFavoriteHandler implements HttpHandler {
+        @Override
+        public void handle(HttpExchange exchange) throws IOException {
+            if (exchange.getRequestMethod().equalsIgnoreCase("POST")) {
+                String requestBody = new String(exchange.getRequestBody().readAllBytes());
+                ObjectMapper mapper = new ObjectMapper();
+                Map<String, String> requestData = mapper.readValue(requestBody, Map.class);
+                String optionId = requestData.get("optionId");
+                String userEmail = requestData.get("user");
+
+                int userId;
+                try {
+                    userId = DatabaseUtil.getUserIdByEmail(userEmail);
+                } catch (SQLException e) {
+                    e.printStackTrace();
+                    sendResponse(exchange, 500, "{\"message\": \"Failed to retrieve user ID.\"}");
+                    return;
+                }
+
+                try {
+                    if (DatabaseUtil.saveFavoriteOption(userId, Integer.parseInt(optionId))) {
+                        sendResponse(exchange, 200, "{\"message\": \"Favorite saved successfully!\"}");
+                    } else {
+                        sendResponse(exchange, 500, "{\"message\": \"Failed to save favorite.\"}");
+                    }
+                } catch (SQLException e) {
+                    e.printStackTrace();
+                    sendResponse(exchange, 500, "{\"message\": \"Failed to save favorite.\"}");
+                }
+            } else {
+                sendResponse(exchange, 405, "{\"message\": \"Method not allowed.\"}");
+            }
+        }
+
+    }
+    static class GetSavedTripsHandler implements HttpHandler {
+        @Override
+        public void handle(HttpExchange exchange) throws IOException {
+            if (exchange.getRequestMethod().equalsIgnoreCase("POST")) {
+                String requestBody = new String(exchange.getRequestBody().readAllBytes());
+                ObjectMapper mapper = new ObjectMapper();
+                Map<String, String> requestData = mapper.readValue(requestBody, Map.class);
+                String userEmail = requestData.get("userEmail");
+
+                int userId;
+                try {
+                    userId = DatabaseUtil.getUserIdByEmail(userEmail);
+                } catch (SQLException e) {
+                    e.printStackTrace();
+                    sendResponse(exchange, 500, "{\"message\": \"Failed to retrieve user ID.\"}");
+                    return;
+                }
+
+                List<Option> savedTrips;
+                try {
+                    savedTrips = DatabaseUtil.getSavedTripsByUser(userId);
+                } catch (SQLException e) {
+                    e.printStackTrace();
+                    sendResponse(exchange, 500, "{\"message\": \"Failed to retrieve saved trips.\"}");
+                    return;
+                }
+
+                String responseJson = mapper.writeValueAsString(Map.of("savedTrips", savedTrips));
+                System.out.println(responseJson);
+                sendResponse(exchange, 200, responseJson);
+            } else {
+                sendResponse(exchange, 405, "{\"message\": \"Method not allowed.\"}");
+            }
+        }
+    }
+    public static LocalDateTime getLastUpdateTime() throws IOException {
+        ClassLoader classLoader = Server.class.getClassLoader();
+        ObjectMapper mapper = new ObjectMapper();
+        JsonNode root = mapper.readTree(new File(classLoader.getResource("lastUpdateTime.json").getFile()));
+        String lastUpdateTimeStr = root.get("lastUpdateTime").asText();
+        return LocalDateTime.parse(lastUpdateTimeStr);
+    }
+    public static void updateLastUpdateTime() throws IOException {
+        LocalDateTime now = LocalDateTime.now();
+        ObjectMapper mapper = new ObjectMapper();
+        ObjectNode rootNode = mapper.createObjectNode();
+        rootNode.put("lastUpdateTime", now.toString());
+
+        File file = new File(Server.class.getClassLoader().getResource("lastUpdateTime.json").getFile());
+
+        mapper.writerWithDefaultPrettyPrinter().writeValue(file, rootNode);
+
+        System.out.println("Last update time saved: " + now);
+    }
+
+    public static void sendResponse(HttpExchange exchange, int statusCode, String response) throws IOException {
+        exchange.getResponseHeaders().add("Cross-Origin-Opener-Policy", "unsafe-none");
+        exchange.getResponseHeaders().add("Cross-Origin-Embedder-Policy", "require-corp");
+        exchange.getResponseHeaders().add("Content-Type", "application/json");
+        exchange.sendResponseHeaders(statusCode, response.length());
+        exchange.getResponseBody().write(response.getBytes());
+        exchange.getResponseBody().close();
+    }
+
+}
+
+
+
+
Index: ckend/GlobeGuru-backend/src/main/java/URLsJSON.json
===================================================================
--- backend/GlobeGuru-backend/src/main/java/URLsJSON.json	(revision d4d8f6155e80421fe9fc8c1ee34e0b784226b96c)
+++ 	(revision )
@@ -1,7 +1,0 @@
-{
-  "agencyurls":
-          [
-            "https://www.fibula.com.mk/",
-            "https://booking.escapetravel.mk/"
-          ]
-}
Index: backend/GlobeGuru-backend/src/main/resources/CountriesList.json
===================================================================
--- backend/GlobeGuru-backend/src/main/resources/CountriesList.json	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ backend/GlobeGuru-backend/src/main/resources/CountriesList.json	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,8 @@
+{
+  "countries": [
+    "Grcija",
+    "Turcija",
+    "Albanija",
+    "Italija"
+  ]
+}
Index: backend/GlobeGuru-backend/src/main/resources/URLsJSON.json
===================================================================
--- backend/GlobeGuru-backend/src/main/resources/URLsJSON.json	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ backend/GlobeGuru-backend/src/main/resources/URLsJSON.json	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,7 @@
+{
+  "agencyurls":
+          [
+            "https://magelantravel.mk/",
+            "https://booking.escapetravel.mk/"
+          ]
+}
Index: backend/GlobeGuru-backend/src/main/resources/lastUpdateTime.json
===================================================================
--- backend/GlobeGuru-backend/src/main/resources/lastUpdateTime.json	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ backend/GlobeGuru-backend/src/main/resources/lastUpdateTime.json	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,3 @@
+{
+  "lastUpdateTime": "2024-12-25T13:45:30"
+}
Index: backend/GlobeGuru-backend/target/classes/CountriesList.json
===================================================================
--- backend/GlobeGuru-backend/target/classes/CountriesList.json	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ backend/GlobeGuru-backend/target/classes/CountriesList.json	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,8 @@
+{
+  "countries": [
+    "Grcija",
+    "Turcija",
+    "Albanija",
+    "Italija"
+  ]
+}
Index: backend/GlobeGuru-backend/target/classes/URLsJSON.json
===================================================================
--- backend/GlobeGuru-backend/target/classes/URLsJSON.json	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ backend/GlobeGuru-backend/target/classes/URLsJSON.json	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,7 @@
+{
+  "agencyurls":
+          [
+            "https://magelantravel.mk/",
+            "https://booking.escapetravel.mk/"
+          ]
+}
Index: backend/GlobeGuru-backend/target/classes/lastUpdateTime.json
===================================================================
--- backend/GlobeGuru-backend/target/classes/lastUpdateTime.json	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ backend/GlobeGuru-backend/target/classes/lastUpdateTime.json	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,3 @@
+{
+  "lastUpdateTime" : "2025-01-09T17:43:12.148699200"
+}
Index: ckend/GlobeGuru-backend/target/classes/main/java/URLsJSON.json
===================================================================
--- backend/GlobeGuru-backend/target/classes/main/java/URLsJSON.json	(revision d4d8f6155e80421fe9fc8c1ee34e0b784226b96c)
+++ 	(revision )
@@ -1,7 +1,0 @@
-{
-  "agencyurls":
-          [
-            "https://www.fibula.com.mk/",
-            "https://booking.escapetravel.mk/"
-          ]
-}
Index: ontend/GlobeGuru-frontend/.idea/.gitignore
===================================================================
--- frontend/GlobeGuru-frontend/.idea/.gitignore	(revision d4d8f6155e80421fe9fc8c1ee34e0b784226b96c)
+++ 	(revision )
@@ -1,5 +1,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Editor-based HTTP Client requests
-/httpRequests/
Index: ontend/GlobeGuru-frontend/.idea/GlobeGuru-frontend.iml
===================================================================
--- frontend/GlobeGuru-frontend/.idea/GlobeGuru-frontend.iml	(revision d4d8f6155e80421fe9fc8c1ee34e0b784226b96c)
+++ 	(revision )
@@ -1,12 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module type="WEB_MODULE" version="4">
-  <component name="NewModuleRootManager">
-    <content url="file://$MODULE_DIR$">
-      <excludeFolder url="file://$MODULE_DIR$/temp" />
-      <excludeFolder url="file://$MODULE_DIR$/.tmp" />
-      <excludeFolder url="file://$MODULE_DIR$/tmp" />
-    </content>
-    <orderEntry type="inheritedJdk" />
-    <orderEntry type="sourceFolder" forTests="false" />
-  </component>
-</module>
Index: ontend/GlobeGuru-frontend/.idea/misc.xml
===================================================================
--- frontend/GlobeGuru-frontend/.idea/misc.xml	(revision d4d8f6155e80421fe9fc8c1ee34e0b784226b96c)
+++ 	(revision )
@@ -1,6 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="MarkdownSettingsMigration">
-    <option name="stateVersion" value="1" />
-  </component>
-</project>
Index: ontend/GlobeGuru-frontend/.idea/modules.xml
===================================================================
--- frontend/GlobeGuru-frontend/.idea/modules.xml	(revision d4d8f6155e80421fe9fc8c1ee34e0b784226b96c)
+++ 	(revision )
@@ -1,8 +1,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="ProjectModuleManager">
-    <modules>
-      <module fileurl="file://$PROJECT_DIR$/.idea/GlobeGuru-frontend.iml" filepath="$PROJECT_DIR$/.idea/GlobeGuru-frontend.iml" />
-    </modules>
-  </component>
-</project>
Index: ontend/GlobeGuru-frontend/public/index.html
===================================================================
--- frontend/GlobeGuru-frontend/public/index.html	(revision d4d8f6155e80421fe9fc8c1ee34e0b784226b96c)
+++ 	(revision )
@@ -1,23 +1,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-    <meta charset="UTF-8">
-    <title>Title</title>
-</head>
-<body>
-    <div class="searchBar">
-        <form action="" method="POST">
-            <label>Дестинација</label>
-            <input type="text">
-            <label>Датум на поаѓање</label>
-            <input type="date">
-            <label>Број на луѓе</label>
-            <input type="number">
-            <input type="submit">
-        </form>
-    </div>
-<div class="givenOptions">
-    <!-- populated with JS response -->
-</div>
-</body>
-</html>
Index: frontend/admin-panel.html
===================================================================
--- frontend/admin-panel.html	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ frontend/admin-panel.html	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Admin Panel</title>
+    <style>
+        body {
+            font-family: Arial, sans-serif;
+            background-color: #f0f0f0;
+            padding: 20px;
+        }
+        .container {
+            max-width: 600px;
+            margin: 0 auto;
+            padding: 20px;
+            background-color: #fff;
+            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
+        }
+        h1 {
+            text-align: center;
+        }
+        button {
+            display: block;
+            width: 100%;
+            padding: 10px;
+            margin: 10px 0;
+            background-color: #4CAF50;
+            color: #fff;
+            border: none;
+            cursor: pointer;
+            font-size: 16px;
+        }
+        button:hover {
+            background-color: #45a049;
+        }
+        .info {
+            margin: 20px 0;
+        }
+        #warning {
+            display: none;
+            position: fixed;
+            top: 50%;
+            left: 50%;
+            transform: translate(-50%, -50%);
+            padding: 20px;
+            background-color: #fff;
+            box-shadow: 0 0 15px rgba(0, 0, 0, 0.3);
+            z-index: 1000;
+            text-align: center;
+        }
+        #warning h1 {
+            color: red;
+            margin-bottom: 10px;
+        }
+        #warning p {
+            margin: 10px 0;
+            font-weight: bold;
+        }
+        #confirmDrop {
+            background-color: red;
+            color: #fff;
+            border: none;
+            padding: 10px;
+            margin: 10px 5px;
+            cursor: pointer;
+        }
+        #cancel {
+            background-color: #4CAF50;
+            color: #fff;
+            border: none;
+            padding: 10px;
+            margin: 10px 5px;
+            cursor: pointer;
+        }
+        #confirmDrop:hover {
+            background-color: darkred;
+        }
+        #cancel:hover {
+            background-color: #45a049;
+        }
+    </style>
+</head>
+<body>
+<div class="container">
+    <h1>Admin Panel</h1>
+    <button id="logoutButton">Logout</button>
+    <button onclick="window.location.href='index.html'">Go to Website</button>
+    <button id="startScraperButton">Update Options</button>
+    <div class="info">
+        <h2>Update Info</h2>
+        <p><strong>Time since last update:</strong> <span id="lastUpdateTime">Calculating...</span></p>
+        <p><strong>Current number of options:</strong> <span id="currentOptionsCount">Fetching...</span></p>
+    </div>
+    <button id="dropOptionsDb" style="background-color: red" onclick="popupConfirm()">DROP OPTION DATABASE</button>
+
+</div>
+<div class="container" id="warning">
+    <h1>WARNING</h1>
+    <p><strong>This deletes all options stored in the database!</strong></p>
+    <p><strong>Are you sure?</strong></p>
+    <button id="confirmDrop" onclick="confirmDrop()">DROP DATABASE</button>
+    <button id="cancel" onclick="popupClose()">CANCEL</button>
+</div>
+<script src="js/AdminPanel.js"></script>
+</body>
+</html>
Index: frontend/css.css
===================================================================
--- frontend/css.css	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ frontend/css.css	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,401 @@
+body {
+    font-family: Arial, sans-serif;
+    background-color: #f4f4f9;
+    color: #333;
+    margin: 0;
+    padding: 0;
+    display: flex;
+    height: 100vh;
+    overflow: hidden; /* Add this to prevent body overflow */
+}
+
+.top-right {
+    position: absolute;
+    top: 20px;
+    right: 20px;
+}
+
+.login-button {
+    background-color: #007bff;
+    color: white;
+    border: none;
+    padding: 10px 20px;
+    border-radius: 5px;
+    cursor: pointer;
+    transition: background-color 0.3s;
+}
+
+.login-button:hover {
+    background-color: #0056b3;
+}
+
+.sidebar {
+    width: 300px;
+    background-color: #ffffff;
+    padding: 20px;
+    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: space-evenly;
+    box-sizing: border-box;
+}
+
+.logo {
+    margin-bottom: 20px;
+}
+
+.logo img {
+    max-width: 100%;
+    height: auto;
+}
+
+.searchBar {
+    width: 100%;
+}
+
+.searchBar form {
+    display: flex;
+    flex-direction: column;
+}
+
+.searchBar label {
+    margin: 10px 0 5px;
+    font-weight: bold;
+}
+
+.searchBar input[type="text"],
+.searchBar input[type="date"],
+.searchBar input[type="number"] {
+    border: 1px solid #ccc;
+    border-radius: 5px;
+    padding: 10px;
+    font-size: 16px;
+    width: 100%;
+    margin-bottom: 20px;
+    box-sizing: border-box;
+}
+
+.searchBar input[type="submit"] {
+    background-color: #007bff;
+    color: #fff;
+    border: none;
+    border-radius: 5px;
+    padding: 10px;
+    font-size: 16px;
+    cursor: pointer;
+    transition: background-color 0.3s ease;
+}
+
+.searchBar input[type="submit"]:hover {
+    background-color: #0056b3;
+}
+
+.content {
+    flex: 1;
+    padding: 20px;
+    overflow-y: auto;
+    overflow-x: hidden; /* Add this to prevent horizontal overflow */
+    box-sizing: border-box;
+}
+
+#givenOptions {
+    width: 100%;
+    margin-top: 20px;
+    padding: 20px;
+    border-radius: 10px;
+    box-sizing: border-box;
+}
+
+.option {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    width: 100%;
+    border: 1px solid #ccc;
+    border-radius: 10px;
+    margin-bottom: 20px;
+    padding: 20px;
+    box-sizing: border-box;
+    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
+    background-color: #f4f4f9;
+    overflow-x: auto; /* Add this to handle overflow within option */
+}
+.btnWrapper{
+    display: flex;
+    flex-direction: column;
+    justify-content: space-evenly;
+}
+
+.favBtn{
+    display: none;
+}
+.image {
+    width: 100%;
+    max-width: 300px;
+    height: auto;
+    border-radius: 10px;
+    margin-bottom: 15px;
+}
+
+.option-details {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    width: calc(100% - 300px); /* Adjust width to fit within option */
+    box-sizing: border-box;
+}
+
+p, h1, h2 {
+    margin: 0;
+    padding: 5px 0;
+    text-align: center;
+}
+
+h1 {
+    font-size: 24px;
+    font-weight: bold;
+}
+
+h2 {
+    font-size: 20px;
+    color: #007bff;
+}
+
+.country {
+    font-size: 18px;
+    color: #555;
+}
+
+.price {
+    font-size: 22px;
+    font-weight: bold;
+    color: #e74c3c;
+}
+
+.loading-overlay {
+    position: fixed;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background-color: rgba(255, 255, 255, 0.8);
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    z-index: 1000;
+    display: none;
+}
+
+.loading-content {
+    text-align: center;
+}
+
+.spinner {
+    border: 8px solid #f3f3f3;
+    border-top: 8px solid #3498db;
+    border-radius: 50%;
+    width: 60px;
+    height: 60px;
+    animation: spin 2s linear infinite;
+}
+
+@keyframes spin {
+    0% { transform: rotate(0deg); }
+    100% { transform: rotate(360deg); }
+}
+
+
+.popup {
+    display: none;
+    position: fixed;
+    z-index: 1000;
+    left: 0;
+    top: 0;
+    width: 100%;
+    height: 100%;
+    overflow: auto;
+    background-color: rgba(0, 0, 0, 0.4);
+}
+
+.popup-content {
+    background-color: #fff;
+    margin: 15% auto;
+    padding: 20px;
+    border: 1px solid #888;
+    width: 80%;
+    max-width: 400px;
+    border-radius: 10px;
+    box-shadow: 0 5px 15px rgba(0,0,0,0.3);
+    text-align: center;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+}
+
+.close {
+    color: #aaa;
+    align-self: flex-end;
+    font-size: 28px;
+    font-weight: bold;
+    cursor: pointer;
+    margin-bottom: 10px;
+}
+
+.close:hover,
+.close:focus {
+    color: black;
+    text-decoration: none;
+}
+
+form {
+    width: 100%;
+}
+
+form label {
+    margin: 10px 0 5px;
+    font-weight: bold;
+    width: 100%;
+    text-align: left;
+}
+
+form input[type="email"],
+form input[type="password"],
+form input[type="text"] {
+    width: 100%;
+    padding: 10px;
+    margin-bottom: 20px;
+    border: 1px solid #ccc;
+    border-radius: 5px;
+    box-sizing: border-box;
+    font-size: 16px;
+}
+
+.button {
+    width: 100%;
+    padding: 10px;
+    margin: 10px 0;
+    background-color: #007bff;
+    color: white;
+    border: none;
+    border-radius: 5px;
+    cursor: pointer;
+    font-size: 16px;
+    transition: background-color 0.3s;
+}
+
+.button:hover {
+    background-color: #0056b3;
+}
+
+.button[type="button"] {
+    background-color: #dd4b39;
+}
+
+.button[type="button"]:hover {
+    background-color: #c23321;
+}
+
+form p {
+    margin-top: 20px;
+    text-align: center;
+}
+
+form a {
+    color: #007bff;
+}
+
+form a:hover {
+    color: #0056b3;
+}
+
+/* Response Messages */
+.response {
+    margin-top: 10px;
+    color: red;
+}
+
+.accDetails {
+    display: none;
+}
+.overlay {
+    display: none;
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    background-color: rgba(0, 0, 0, 0.7);
+    z-index: 1000;
+}
+
+.overlay-content {
+    position: relative;
+    margin: 5% auto;
+    padding: 20px;
+    width: 80%;
+    max-width: 1000px;
+    background-color: #fff;
+    display: flex;
+    justify-content: space-between;
+}
+
+.close {
+    position: absolute;
+    top: 10px;
+    right: 25px;
+    color: #aaa;
+    font-size: 35px;
+    font-weight: bold;
+    cursor: pointer;
+}
+
+.close:hover,
+.close:focus {
+    color: #000;
+    text-decoration: none;
+    cursor: pointer;
+}
+
+.saved-trips-container,
+.price-changes-container {
+    width: 48%;
+    overflow-y: auto;
+    max-height: 600px;
+}
+
+h2 {
+    text-align: center;
+}
+
+#savedTripsList,
+#priceChangesList {
+    list-style-type: none;
+    padding: 0;
+}
+
+#savedTripsList .option,
+#priceChangesList .price-change {
+    padding: 10px;
+    margin: 10px 0;
+    border: 1px solid #ccc;
+    border-radius: 5px;
+    background-color: #f4f4f9;
+}
+.btn {
+    margin: 15px;
+    width: 200px;
+    height: 30px;
+    background-color: #007bff;
+    color: white;
+    border: none;
+    border-radius: 5px;
+    cursor: pointer;
+    transition: background-color 0.3s;
+}
+
+.btn:disabled {
+    background-color: grey;
+    cursor: not-allowed;
+    opacity: 0.65;
+}
Index: frontend/index.html
===================================================================
--- frontend/index.html	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ frontend/index.html	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,130 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta http-equiv="Cross-Origin-Opener-Policy" content="unsafe-none">
+
+    <title>GlobeGuru</title>
+    <link rel="stylesheet" href="css.css">
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
+    <link rel="icon" type="image/x-icon" href="images/GLOBE.png">
+</head>
+<body>
+<div id="g_id_onload"
+     data-client_id="376204422797-s8f05nn6drmec1cko2h4kg1nk24abgc9.apps.googleusercontent.com"
+     data-context="signin"
+     data-ux_mode="popup"
+     data-login_uri="http://localhost:8000/"
+     data-callback="handleCredentialResponse"
+     data-auto_prompt="false">
+</div>
+
+<div class="top-right">
+    <button id="loginButton" class="login-button" onclick="openLoginPopup()">Login</button>
+    <button id="logoutButton" class="login-button" style="display:none;" onclick="logout()">Logout</button>
+    <button id="adminPanelButton" class="login-button" style="display:none;" onclick="goToAdminPanel()">Admin Panel</button>
+</div>
+<div class="sidebar">
+    <div class="logo">
+        <img src="images/GLOBE.png" height="235" width="235"/>
+    </div>
+    <div class="searchBar">
+        <form id="form-id">
+            <label for="destination">Дестинација</label>
+            <input type="text" id="destination" name="destination" placeholder="Име на хотел/Град или Држава">
+            <label for="departureDate">Датум на поаѓање</label>
+            <input type="date" id="departureDate" name="departureDate">
+            <label for="Nights">Број на ноќи</label>
+            <input type="number" id="Nights" name="nightsNumber">
+            <input type="submit" class="button" value="Пребарај" >
+        </form>
+    </div>
+    <button id="savedTripsButton" style="display:none;" class="button">Зачувани патувања</button>
+    <button class="button" style="width: 50px; height: 50px; margin-right: auto; display: none;" onclick="openAccountDetails()" id="accBtn"> <i class="fa fa-light fa-user fa-2x"></i></button>
+</div>
+<div class="content">
+    <div id="givenOptions">
+        <!-- populated with JS response -->
+    </div>
+</div>
+<div id="savedTripsOverlay" class="overlay">
+    <div class="overlay-content">
+        <span class="close">&times;</span>
+        <div class="saved-trips-container">
+            <h2>Saved Trips</h2>
+            <div id="savedTripsList"></div>
+        </div>
+        <div class="price-changes-container">
+            <h2>Price Changes</h2>
+            <div id="priceChangesList"></div>
+        </div>
+    </div>
+</div>
+
+<div id="loginPopup" class="popup">
+    <div class="popup-content">
+        <span class="close" onclick="closeLoginPopup()">&times;</span>
+        <h2>Login</h2>
+        <form id="loginForm">
+            <label for="email">Email:</label>
+            <input type="email" id="email" name="email" required>
+            <label for="password">Password:</label>
+            <input type="password" id="password" name="password" autocomplete="on" required>
+            <button type="submit" class="button">Login</button>
+            <div class="g_id_signin"
+                 data-type="icon"
+                 data-shape="square"
+                 data-theme="filled_blue"
+                 data-text="signin_with"
+                 data-size="large" style="margin-left: auto;margin-right: auto;width: 44px;">
+            </div>
+            <p>Don't have an account? <a href="#" onclick="openRegisterPopup()">Register</a></p>
+        </form>
+        <div id="loginResponse" class="response"></div>
+    </div>
+</div>
+
+<div id="registerPopup" class="popup">
+    <div class="popup-content">
+        <span class="close" onclick="closeRegisterPopup()">&times;</span>
+        <h2>Register</h2>
+        <form id="registerForm">
+            <label for="username">Username:</label>
+            <input type="text" id="username" name="username" required>
+            <label for="email">Email:</label>
+            <input type="email" id="email-reg" name="email" required>
+            <label for="password">Password:</label>
+            <input type="password" id="pass-reg" name="password"  autocomplete="on" required>
+            <button type="submit" class="button">Register</button>
+        </form>
+        <div id="registerResponse" class="response"></div>
+    </div>
+</div>
+
+<div id="loadingOverlay" class="loading-overlay">
+    <div class="loading-content">
+        <div class="spinner"></div>
+        <p>Loading, please wait...</p>
+    </div>
+</div>
+<div id="AccountDetailsOverlay" class="popup accDetails">
+    <div class="popup-content">
+        <h1>My account</h1>
+        <div class="popup-content" style="display: none" id="confDel">
+            <div class="delete" >
+                <h1>Are you sure you want to delete your account?</h1>
+                <button onclick="deleteAccount()" class="button" id="confirmDelete" style="background-color: red">Yes</button>
+                <button id="cancel" class="button" onclick="closeConfirmDelete()">No</button>
+            </div>
+        </div>
+        <button class="button" id="pswdChange">Change password</button>
+        <button class="button" style="background-color: red" id="deleteAcc" onclick="confirmDelete()">Delete Account</button>
+    </div>
+</div>
+<script src="js/formHandler.js"></script>
+<script src="js/loginHandler.js"></script>
+<script src="js/siteFlow.js"></script>
+<script src="https://accounts.google.com/gsi/client" async defer></script>
+
+</body>
+</html>
Index: frontend/js/AdminPanel.js
===================================================================
--- frontend/js/AdminPanel.js	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ frontend/js/AdminPanel.js	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,49 @@
+document.getElementById('startScraperButton').addEventListener('click', function() {
+
+    fetch('/admin/start-scraper', { method: 'POST' })
+        .then(response => response.json())
+        .then(data => alert(data.message))
+        .catch(error => console.error('Error:', error));
+
+    fetchLastUpdateTime();
+});
+function popupConfirm(){
+    const div = document.getElementById('warning').style.display = 'block';
+}
+function popupClose(){
+    const div = document.getElementById('warning').style.display = 'none';
+}
+document.getElementById('confirmDrop').addEventListener('click', function() {
+
+    fetch('/admin/drop-db', {method: 'GET'}).then(r => alert("Database dropped")).catch(err => console.error(err));
+    popupClose();
+});
+function fetchLastUpdateTime() {
+    fetch('/admin/last-update-time')
+        .then(response => response.json())
+        .then(data => {
+            document.getElementById('lastUpdateTime').textContent = new Date(data.lastUpdateTime).toLocaleString();
+        })
+        .catch(error => console.error('Error fetching last update time:', error));
+}
+function fetchCurrentOptionsCount() {
+    fetch('/admin/current-options-count')
+        .then(response => response.json())
+        .then(data => {
+            document.getElementById('currentOptionsCount').textContent = data.currentOptionsCount;
+        })
+        .catch(error => console.error('Error fetching current options count:', error));
+}
+
+// Fetch data when the page loads
+document.addEventListener('DOMContentLoaded', function() {
+    fetchLastUpdateTime();
+    fetchCurrentOptionsCount();
+});
+
+
+document.getElementById('logoutButton').addEventListener('click', function() {
+    sessionStorage.removeItem('loggedIn');
+    sessionStorage.removeItem('userEmail');
+    window.location.href = 'index.html'; // Redirect
+});
Index: frontend/js/formHandler.js
===================================================================
--- frontend/js/formHandler.js	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ frontend/js/formHandler.js	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,137 @@
+document.addEventListener('DOMContentLoaded', function() {
+    const form = document.getElementById('form-id'); // Ensure the form has the correct ID
+    const loadingOverlay = document.getElementById('loadingOverlay');
+
+    form.addEventListener('submit', function(event) {
+        event.preventDefault(); // Prevent the default form submission
+
+        // Collect form data
+        const formData = new FormData(form);
+        const data = {};
+        let isValid = true;
+        let errorMessage = "";
+
+        // Validate form data
+        formData.forEach((value, key) => {
+            data[key] = value;
+            if (key === "departureDate") {
+                const today = new Date();
+                const departureDate = new Date(value);
+                if (departureDate <= today) {
+                    isValid = false;
+                    errorMessage += "Датумот на поаѓање е грешен!.\n";
+                }
+            }
+            if (key === "destination" && !value) {
+                isValid = false;
+                errorMessage += "Внесете дестинација.\n";
+            }
+
+        });
+
+        if (!isValid) {
+            alert(errorMessage);
+            return;
+        }
+
+        // Show the loading overlay
+        loadingOverlay.style.display = 'flex';
+
+        // Send form data to the server
+        fetch('/submit', {
+            method: 'POST',
+            headers: {
+                'Content-Type': 'application/json'
+            },
+            body: JSON.stringify(data)
+        })
+            .then(response => response.json())
+            .then(data => {
+
+                loadingOverlay.style.display = 'none';
+
+                const dataList = document.getElementById('givenOptions');
+                dataList.innerHTML = '';
+                if (data.length === 0) {
+                    const wrapper = document.createElement('div');
+                    const text = document.createElement('p');
+                    text.textContent = "Не се пронајдени резултати за вашето пребарување!";
+                    wrapper.appendChild(text);
+                    dataList.appendChild(wrapper);
+                }
+                data.forEach(item => {
+
+                    const optionDiv = document.createElement('div');
+                    optionDiv.classList.add('option');
+                    //Option from
+
+                    //image
+                    const img = document.createElement('img');
+                    img.classList.add('image');
+                    img.src = item.imgSrc; // Use item.imageSrc if available
+                    optionDiv.appendChild(img);
+                    const WrapperDiv = document.createElement('div');
+                    optionDiv.appendChild(WrapperDiv);
+                    //hotel
+                    const nameParagraph = document.createElement('p');
+                    nameParagraph.id = 'name';
+                    nameParagraph.textContent = item.hotelName;
+                    WrapperDiv.appendChild(nameParagraph);
+
+                    //Destination
+                    const countryParagraph = document.createElement('p');
+                    countryParagraph.id = 'country';
+                    countryParagraph.style.fontSize = '20px';
+                    countryParagraph.textContent = item.country;
+                    WrapperDiv.appendChild(countryParagraph);
+                    const dateParagraph = document.createElement('h2');
+                    dateParagraph.id = 'date';
+                    dateParagraph.textContent = item.dateRange;
+                    WrapperDiv.appendChild(dateParagraph);
+                    //price
+                    const priceHeading = document.createElement('h1');
+                    priceHeading.textContent = 'Цена:';
+                    WrapperDiv.appendChild(priceHeading);
+                    const priceParagraph = document.createElement('h2');
+                    priceParagraph.id = 'price';
+                    priceParagraph.textContent = item.price + "EUR";
+                    WrapperDiv.appendChild(priceParagraph);
+
+                    //  link and button
+                    const link = document.createElement('a');
+                    link.id = 'link';
+                    link.href = item.link; // Use item.link if available
+                    link.target = '_blank'; // Open link in new tab
+
+                    const button = document.createElement('button');
+                    button.classList.add('btn', 'login-button');
+                    button.textContent = 'Линк до страна';
+                    const btnWrapDiv = document.createElement('div');
+                    btnWrapDiv.classList.add('btnWrapper');
+                    const favBtn = document.createElement('button');
+                    favBtn.classList.add('favBtn','btn');
+                    favBtn.id = 'favBtnId';
+                    favBtn.textContent = 'Додадете во омилени';
+                    favBtn.setAttribute('data-option-id', item.id);
+                    favBtn.addEventListener('click', function () {
+                        const optionId = this.getAttribute('data-option-id');
+                        saveFavoriteOption(optionId);
+                    });
+
+                    btnWrapDiv.appendChild(link);
+                    link.appendChild(button);
+                    btnWrapDiv.appendChild(favBtn);
+
+                    optionDiv.appendChild(btnWrapDiv);
+                    // Append option div to dataList
+                    dataList.appendChild(optionDiv);
+                });
+                updateFavoriteButtons();
+            })
+            .catch(error => {
+                console.error('Error fetching data:', error);
+                // Hide the loading overlay in case of error
+                loadingOverlay.style.display = 'none';
+            });
+    });
+});
Index: frontend/js/loginHandler.js
===================================================================
--- frontend/js/loginHandler.js	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ frontend/js/loginHandler.js	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,154 @@
+document.addEventListener('DOMContentLoaded', function() {
+    const loginForm = document.getElementById('loginForm');
+    const registerForm = document.getElementById('registerForm');
+    const loginResponse = document.getElementById('loginResponse');
+    const registerResponse = document.getElementById('registerResponse');
+
+    checkSession();
+
+    loginForm.addEventListener('submit', function(event) {
+        event.preventDefault();
+
+        const email = loginForm.email.value;
+        const password = loginForm.password.value;
+
+        const data = {
+            email: email,
+            password: password
+        };
+
+        fetch('/account/login', {
+            method: 'POST',
+            headers: {
+                'Content-Type': 'application/json'
+            },
+            body: JSON.stringify(data)
+        })
+            .then(response => response.json())
+            .then(data => {
+                if (data.sessionId) {
+                    loginResponse.textContent = data.message;
+                    sessionStorage.setItem('loggedIn', 'true');
+                    sessionStorage.setItem('user', JSON.stringify(email));
+                    sessionStorage.setItem('isAdmin', data.isAdmin);
+                    document.cookie = `sessionId=${data.sessionId}; path=/`;
+                    showLoggedInState();
+                    closeLoginPopup();
+                } else {
+                    throw new Error(data.message);
+                }
+            })
+            .catch(error => {
+                showMessage('loginResponse', 'error', error.message);
+            });
+    });
+
+    registerForm.addEventListener('submit', function(event) {
+        event.preventDefault();
+
+        const username = registerForm.username.value;
+        const email = registerForm.email.value;
+        const password = registerForm.password.value;
+
+        const data = {
+            username: username,
+            email: email,
+            password: password
+        };
+
+        fetch('/account/register', {
+            method: 'POST',
+            headers: {
+                'Content-Type': 'application/json'
+            },
+            body: JSON.stringify(data)
+        })
+            .then(response => response.json())
+            .then(data => {
+                if (response.ok) {
+                    showMessage('registerResponse', 'success', data.message);
+                    closeRegisterPopup();
+                } else {
+                    throw new Error(data.message);
+                }
+            })
+            .catch(error => {
+                showMessage('registerResponse', 'error', error.message);
+            });
+    });
+});
+
+function checkSession() {
+    fetch('/account/session', {
+        method: 'GET',
+        credentials: 'include'
+    })
+        .then(response => response.json())
+        .then(data => {
+            if (data.loggedIn) {
+                sessionStorage.setItem('loggedIn', 'true');
+                sessionStorage.setItem('user', JSON.stringify(data.user));
+                sessionStorage.setItem('isAdmin', data.isAdmin);
+                showLoggedInState();
+            } else {
+                sessionStorage.clear();
+                showLoggedOutState();
+            }
+        })
+        .catch(error => {
+            console.error('Error checking session:', error);
+            sessionStorage.clear();
+            showLoggedOutState();
+        });
+}
+
+function logout() {
+    fetch('/account/logout', {
+        method: 'POST',
+        credentials: 'include'
+    })
+        .then(response => {
+            if (response.ok) {
+                sessionStorage.clear();
+                document.cookie = "sessionId=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
+                showLoggedOutState();
+            } else {
+                throw new Error('Logout failed');
+            }
+        })
+        .catch(error => {
+            console.error('Error logging out:', error);
+        });
+}
+
+
+function handleCredentialResponse(response) {
+    const email = JSON.parse(atob(response.credential.split('.')[1])).email;
+    fetch('/account/login', {
+        method: 'POST',
+        headers: {
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify({ id_token: response.credential })
+    })
+        .then(response => response.json())
+        .then(data => {
+            if (data.sessionId) {
+                sessionStorage.setItem('loggedIn', 'true');
+                sessionStorage.setItem('user', JSON.stringify(email));
+                sessionStorage.setItem('isAdmin', data.isAdmin);
+                document.cookie = `sessionId=${data.sessionId}; path=/`;
+                showLoggedInState();
+                closeLoginPopup();
+            } else {
+                throw new Error(data.message);
+            }
+        })
+        .catch(error => {
+            console.error(error);
+            showMessage('loginResponse', 'error', 'Google login failed');
+        });
+}
+
+
+
Index: frontend/js/siteFlow.js
===================================================================
--- frontend/js/siteFlow.js	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ frontend/js/siteFlow.js	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,290 @@
+function getUserDetails() {
+    return JSON.parse(sessionStorage.getItem('user'));
+}
+
+function deleteAccount() {
+    fetch('/delete-account', {
+        method: 'POST',
+        headers: {
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify(getUserDetails())
+    })
+        .then(response => response.json())
+        .then(data => {
+            if (data.success) {
+                sessionStorage.clear();
+                logout();
+                alert('Account deleted successfully');
+            } else {
+                alert('Failed to delete account: ' + data.message);
+            }
+        })
+        .catch(error => {
+            console.error('Error:', error);
+            alert('Failed to delete account: ' + error.message);
+        });
+}
+
+function logout() {
+    sessionStorage.clear();
+    document.cookie = "sessionId=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
+    showLoggedOutState();
+    fetch('/account/logout', {
+        method: 'POST',
+        credentials: 'include'
+    });
+}
+
+function openAccountDetails() {
+    document.getElementById('AccountDetailsOverlay').style.display = 'block';
+}
+
+function confirmDelete() {
+    document.getElementById('confDel').style.display = 'block';
+}
+
+function closeConfirmDelete() {
+    document.getElementById('confDel').style.display = 'none';
+}
+
+function openLoginPopup() {
+    document.getElementById('loginPopup').style.display = 'block';
+}
+
+function closeLoginPopup() {
+    document.getElementById('loginPopup').style.display = 'none';
+}
+
+function openRegisterPopup() {
+    document.getElementById('registerPopup').style.display = 'block';
+}
+
+function closeRegisterPopup() {
+    document.getElementById('registerPopup').style.display = 'none';
+}
+
+function showLoggedInState() {
+    document.getElementById('loginButton').style.display = 'none';
+    document.getElementById('logoutButton').style.display = 'block';
+    document.getElementById('savedTripsButton').style.display = 'block';
+    document.getElementById('accBtn').style.display = 'block';
+
+    var style = document.createElement('style');
+    style.innerHTML = '.favBtn { display: block; }';
+    document.head.appendChild(style);
+
+    if (sessionStorage.getItem('isAdmin') === 'true') {
+        document.getElementById('adminPanelButton').style.display = 'block';
+    }
+}
+
+
+function showMessage(elementId, type, message) {
+    const element = document.getElementById(elementId);
+    if (!element) {
+        console.error(`Element with id ${elementId} not found`);
+        return;
+    }
+    element.textContent = message;
+    element.className = `message ${type}`;
+}
+
+
+function showLoggedOutState() {
+    document.getElementById('loginButton').style.display = 'block';
+    document.getElementById('logoutButton').style.display = 'none';
+    document.getElementById('savedTripsButton').style.display = 'none';
+    document.getElementById('accBtn').style.display = 'none';
+    var style = document.createElement('style');
+    style.innerHTML = '.favBtn { display: none; }';
+    document.head.appendChild(style);
+    document.getElementById('loginResponse').style.display = 'none';
+    document.getElementById('adminPanelButton').style.display = 'none';
+}
+
+function goToAdminPanel() {
+    window.location.href = '/admin-panel';
+}
+function showLoginFeedback(success, message) {
+    const loginResponse = document.getElementById('loginResponse');
+    loginResponse.textContent = message;
+    loginResponse.style.color = success ? 'green' : 'red';
+    loginResponse.style.display = 'block';
+}
+
+window.onclick = function(event) {
+    const loginPopup = document.getElementById('loginPopup');
+    const registerPopup = document.getElementById('registerPopup');
+    const accountPopup = document.getElementById('AccountDetailsOverlay');
+    if (event.target === loginPopup) {
+        loginPopup.style.display = 'none';
+    }
+    if (event.target === registerPopup) {
+        registerPopup.style.display = 'none';
+    }
+    if (event.target === accountPopup) {
+        accountPopup.style.display = 'none';
+    }
+}
+
+document.addEventListener('DOMContentLoaded', function() {
+    checkSession();
+
+    document.querySelectorAll('.favBtn').forEach(button => {
+        button.addEventListener('click', function() {
+            const optionId = this.getAttribute('data-option-id');
+            saveFavoriteOption(optionId);
+        });
+    });
+
+    document.getElementById('savedTripsButton').addEventListener('click', function() {
+        document.getElementById('savedTripsOverlay').style.display = 'block';
+        fetchSavedTrips();
+        //fetchPriceChanges();
+    });
+
+    document.querySelector('.close').addEventListener('click', function() {
+        document.getElementById('savedTripsOverlay').style.display = 'none';
+    });
+});
+
+
+function saveFavoriteOption(optionId) {
+    const mail = sessionStorage.getItem('user').replace(/^"|"$/g, '');
+    fetch('/save-favorite', {
+        method: 'POST',
+        headers: {
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify({ optionId: optionId, user: mail })
+    })
+        .then(response => {
+            if (response.ok) {
+                return response.json();
+            }
+            throw new Error('Network response was not ok.');
+        })
+        .then(data => {
+            console.log('Option saved:', data);
+            // Update the UI to reflect that the option was saved
+            updateFavoriteButtons();
+        })
+        .catch(error => {
+            console.error('Error:', error);
+        });
+}
+
+function updateFavoriteButtons() {
+    const mail = sessionStorage.getItem('user').replace(/^"|"$/g, '');
+    fetch('/get-saved-trips', {
+        method: 'POST',
+        headers: {
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify({ userEmail: mail })
+    })
+        .then(response => response.json())
+        .then(data => {
+            // Extract the option IDs of saved trips
+            const savedOptionIds = data.savedTrips.map(trip => trip.id);
+
+            document.querySelectorAll('.favBtn').forEach(button => {
+                const optionId = parseInt(button.getAttribute('data-option-id'), 10);
+                if (savedOptionIds.includes(optionId)) {
+                    button.disabled = true;
+                    button.textContent = 'Зачувано';
+                } else {
+                    button.disabled = false;
+                    button.textContent = 'Додадете во омилени';
+                }
+            });
+        })
+        .catch(error => {
+            console.error('Error fetching saved options:', error);
+        });
+}
+
+function fetchSavedTrips() {
+    const userEmail = sessionStorage.getItem('user').replace(/^"|"$/g, '');
+    fetch('/get-saved-trips', {
+        method: 'POST',
+        headers: {
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify({ userEmail: userEmail })
+    })
+        .then(response => response.json())
+        .then(data => {
+
+            const savedTripsList = document.getElementById('savedTripsList');
+            savedTripsList.innerHTML = '';
+            data.savedTrips.forEach(trip => {
+                const tripDiv = document.createElement('div');
+                tripDiv.classList.add('option');
+
+                const closeButton = document.createElement('button');
+                closeButton.classList.add('remove-option');
+                closeButton.textContent = '×';
+                closeButton.onclick = function() {
+                    removeFromSaved(trip.id);
+                };
+                tripDiv.appendChild(closeButton);
+
+                const hotelName = document.createElement('p');
+                hotelName.textContent = trip.hotelName;
+                const country = document.createElement('p');
+                country.textContent = trip.country;
+                const price = document.createElement('p');
+                price.textContent = trip.price + "€";
+
+                tripDiv.appendChild(hotelName);
+                tripDiv.appendChild(country);
+                tripDiv.appendChild(price);
+
+                savedTripsList.appendChild(tripDiv);
+            });
+
+
+            const priceChangesList = document.getElementById('priceChangesList');
+            priceChangesList.innerHTML = '';
+            const priceChanges = data.savedTrips.filter(trip => trip.priceChanged);
+            if (priceChanges.length > 0) {
+                priceChanges.forEach(change => {
+                    const changeDiv = document.createElement('div');
+                    changeDiv.classList.add('price-change');
+                    changeDiv.textContent = `Цената на ${change.hotelName} има промена од ${change.price}€ во ${change.newPrice}€`;
+                    priceChangesList.appendChild(changeDiv);
+                });
+            } else {
+                priceChangesList.textContent = "нема промена на цената.";
+            }
+        })
+        .catch(error => {
+            console.error('Error fetching saved trips:', error);
+        });
+}
+function removeFromSaved(optionId) {
+    const userEmail = sessionStorage.getItem('user').replace(/^"|"$/g, '');
+    fetch('/remove-from-saved', {
+        method: 'POST',
+        headers: {
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify({ optionId: optionId, userEmail: userEmail })
+    })
+        .then(response => {
+            if (response.ok) {
+                return response.json();
+            }
+            throw new Error('Network response was not ok.');
+        })
+        .then(data => {
+            if (data.success) {
+                fetchSavedTrips();
+            }
+        })
+        .catch(error => {
+            console.error('Error:', error);
+        });
+}
Index: frontend/package.json
===================================================================
--- frontend/package.json	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
+++ frontend/package.json	(revision c164f8f00c59f28d9cb253011c0a27c7471171ee)
@@ -0,0 +1,6 @@
+{
+  "name": "frontend",
+  "version": "1.0.0",
+  "dependencies": {
+  }
+}
