#!/usr/bin/env python3
"""
BlackBerry Passport Level & Elevation App
A digital level and elevation tool using gyroscope and accelerometer sensors.
Optimized for BlackBerry Passport with ES5-compatible JavaScript.
"""
import http.server
import socketserver
import json
import os
import sys
import time
import threading
import sqlite3
from datetime import datetime

PORT = 8027
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DB_PATH = os.path.join(BASE_DIR, 'level_data.db')

# Initialize database for storing measurements
def init_database():
    """Initialize SQLite database for storing level measurements"""
    conn = sqlite3.connect(DB_PATH)
    cursor = conn.cursor()
    
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS measurements (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            pitch REAL,
            roll REAL,
            elevation REAL,
            compass_heading REAL,
            location_name TEXT,
            notes TEXT
        )
    ''')
    
    conn.commit()
    conn.close()

# Embedded HTML content optimized for BlackBerry Passport
HTML_CONTENT = '''<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="initial-scale=1, user-scalable=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <title>Level & Elevation - BB10</title>
    <style>
        /* BlackBerry Passport Optimized Styles */
        body {
            background-color: #1e1e1e;
            color: white;
            font-family: "Slate Pro", Slate, "Myriad Pro", Helvetica, Arial, sans-serif;
            font-size: 14px;
            margin: 0;
            padding: 0;
            overflow-x: hidden;
            user-select: none;
            -webkit-user-select: none;
            -webkit-touch-callout: none;
        }
        
        .header {
            background-color: #2b2b2b;
            border-bottom: 2px solid #00769e;
            padding: 15px;
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            z-index: 1000;
            display: flex;
            justify-content: space-between;
            align-items: center;
            height: 50px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.3);
        }
        
        .header h1 {
            margin: 0;
            font-size: 18px;
            font-weight: normal;
            flex: 1;
            text-align: center;
        }
        
        .calibration-status {
            width: 12px;
            height: 12px;
            border-radius: 50%;
            background-color: #f44336;
            margin-right: 10px;
        }
        
        .calibration-status.calibrated {
            background-color: #4CAF50;
        }
        
        .content {
            padding: 80px 15px 20px 15px;
            min-height: calc(100vh - 100px);
        }
        
        /* Digital Level Display */
        .level-container {
            background-color: #2b2b2b;
            border: 2px solid #00769e;
            border-radius: 12px;
            padding: 20px;
            margin-bottom: 20px;
            text-align: center;
        }
        
        .level-display {
            position: relative;
            width: 280px;
            height: 280px;
            margin: 0 auto 20px auto;
            background: radial-gradient(circle, #333 0%, #1e1e1e 100%);
            border-radius: 50%;
            border: 3px solid #00769e;
            overflow: hidden;
        }
        
        .level-bubble {
            position: absolute;
            width: 20px;
            height: 20px;
            background: #4CAF50;
            border-radius: 50%;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            transition: all 0.1s ease;
            box-shadow: 0 0 10px rgba(76, 175, 80, 0.5);
        }
        
        .level-crosshairs {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 60px;
            height: 60px;
            border: 2px solid #00769e;
            border-radius: 50%;
            opacity: 0.7;
        }
        
        .level-crosshairs::before,
        .level-crosshairs::after {
            content: '';
            position: absolute;
            background-color: #00769e;
        }
        
        .level-crosshairs::before {
            width: 2px;
            height: 100%;
            left: 50%;
            top: 0;
            transform: translateX(-50%);
        }
        
        .level-crosshairs::after {
            width: 100%;
            height: 2px;
            top: 50%;
            left: 0;
            transform: translateY(-50%);
        }
        
        .level-readings {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 15px;
            margin-bottom: 20px;
        }
        
        .reading-card {
            background-color: #333;
            border: 1px solid #555;
            border-radius: 8px;
            padding: 15px;
            text-align: center;
        }
        
        .reading-value {
            font-size: 24px;
            font-weight: bold;
            color: #00769e;
            margin-bottom: 5px;
        }
        
        .reading-label {
            font-size: 12px;
            color: #aaa;
        }
        
        .level-status {
            font-size: 16px;
            font-weight: bold;
            margin: 15px 0;
            padding: 10px;
            border-radius: 6px;
            background-color: #333;
        }
        
        .level-status.level {
            background-color: #4CAF50;
            color: white;
        }
        
        .level-status.tilted {
            background-color: #ff9800;
            color: white;
        }
        
        /* Compass Display */
        .compass-container {
            background-color: #2b2b2b;
            border: 2px solid #00769e;
            border-radius: 12px;
            padding: 20px;
            margin-bottom: 20px;
            text-align: center;
        }
        
        .compass-display {
            position: relative;
            width: 200px;
            height: 200px;
            margin: 0 auto 15px auto;
            background: radial-gradient(circle, #333 0%, #1e1e1e 100%);
            border-radius: 50%;
            border: 3px solid #00769e;
        }
        
        .compass-needle {
            position: absolute;
            top: 50%;
            left: 50%;
            width: 4px;
            height: 80px;
            background: linear-gradient(to bottom, #f44336 0%, #f44336 50%, #4CAF50 50%, #4CAF50 100%);
            transform-origin: bottom center;
            transform: translate(-50%, -100%);
            transition: transform 0.3s ease;
            border-radius: 2px;
        }
        
        .compass-directions {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
        }
        
        .compass-direction {
            position: absolute;
            font-size: 14px;
            font-weight: bold;
            color: #00769e;
        }
        
        .compass-direction.north {
            top: 10px;
            left: 50%;
            transform: translateX(-50%);
        }
        
        .compass-direction.east {
            right: 10px;
            top: 50%;
            transform: translateY(-50%);
        }
        
        .compass-direction.south {
            bottom: 10px;
            left: 50%;
            transform: translateX(-50%);
        }
        
        .compass-direction.west {
            left: 10px;
            top: 50%;
            transform: translateY(-50%);
        }
        
        .compass-heading {
            font-size: 20px;
            font-weight: bold;
            color: #00769e;
            margin: 10px 0;
        }
        
        /* Control Buttons */
        .controls {
            display: flex;
            gap: 10px;
            margin-bottom: 20px;
        }
        
        .btn {
            flex: 1;
            padding: 12px;
            background-color: #00769e;
            color: white;
            border: none;
            border-radius: 6px;
            font-size: 14px;
            cursor: pointer;
            transition: background-color 0.2s;
            font-family: inherit;
        }
        
        .btn:hover {
            background-color: #005f7a;
        }
        
        .btn:active {
            transform: scale(0.98);
        }
        
        .btn.secondary {
            background-color: #444;
        }
        
        .btn.secondary:hover {
            background-color: #555;
        }
        
        /* Measurement History */
        .history-container {
            background-color: #2b2b2b;
            border: 1px solid #444;
            border-radius: 8px;
            padding: 15px;
            margin-bottom: 20px;
        }
        
        .history-header {
            font-size: 16px;
            font-weight: bold;
            margin-bottom: 15px;
            color: #00769e;
        }
        
        .history-entry {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 8px 0;
            border-bottom: 1px solid #444;
        }
        
        .history-entry:last-child {
            border-bottom: none;
        }
        
        .history-time {
            font-size: 12px;
            color: #888;
        }
        
        .history-values {
            font-size: 12px;
            color: #00769e;
            font-family: monospace;
        }
        
        /* Sensor Status */
        .sensor-status {
            background-color: #2b2b2b;
            border: 1px solid #444;
            border-radius: 8px;
            padding: 15px;
        }
        
        .sensor-info {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 8px;
        }
        
        .sensor-label {
            font-size: 12px;
            color: #aaa;
        }
        
        .sensor-value {
            font-size: 12px;
            color: #00769e;
            font-family: monospace;
        }
        
        /* Responsive adjustments */
        @media (max-width: 480px) {
            .level-display {
                width: 240px;
                height: 240px;
            }
            
            .compass-display {
                width: 160px;
                height: 160px;
            }
            
            .controls {
                flex-direction: column;
            }
        }
        
        /* Landscape mode optimizations */
        @media (orientation: landscape) {
            .content {
                padding: 70px 10px 10px 10px;
            }
            
            .level-readings {
                grid-template-columns: repeat(4, 1fr);
            }
        }
        
        .error-message {
            background-color: #f44336;
            color: white;
            padding: 10px;
            border-radius: 4px;
            margin: 10px 0;
            text-align: center;
        }
        
        .success-message {
            background-color: #4CAF50;
            color: white;
            padding: 10px;
            border-radius: 4px;
            margin: 10px 0;
            text-align: center;
        }
    </style>
</head>
<body>
    <div class="header">
        <h1>Level & Elevation</h1>
        <div class="calibration-status" id="calibrationStatus"></div>
    </div>
    
    <div class="content">
        <!-- Digital Level Display -->
        <div class="level-container">
            <div class="level-display" id="levelDisplay">
                <div class="level-crosshairs"></div>
                <div class="level-bubble" id="levelBubble"></div>
            </div>
            
            <div class="level-readings">
                <div class="reading-card">
                    <div class="reading-value" id="pitchValue">0.0°</div>
                    <div class="reading-label">Pitch (Forward/Back)</div>
                </div>
                <div class="reading-card">
                    <div class="reading-value" id="rollValue">0.0°</div>
                    <div class="reading-label">Roll (Left/Right)</div>
                </div>
                <div class="reading-card">
                    <div class="reading-value" id="elevationValue">0.0°</div>
                    <div class="reading-label">Elevation Angle</div>
                </div>
                <div class="reading-card">
                    <div class="reading-value" id="accuracyValue">--</div>
                    <div class="reading-label">Accuracy</div>
                </div>
            </div>
            
            <div class="level-status" id="levelStatus">Initializing...</div>
        </div>
        
        <!-- Compass Display -->
        <div class="compass-container">
            <div class="compass-display" id="compassDisplay">
                <div class="compass-needle" id="compassNeedle"></div>
                <div class="compass-directions">
                    <div class="compass-direction north">N</div>
                    <div class="compass-direction east">E</div>
                    <div class="compass-direction south">S</div>
                    <div class="compass-direction west">W</div>
                </div>
            </div>
            <div class="compass-heading" id="compassHeading">--- °</div>
        </div>
        
        <!-- Control Buttons -->
        <div class="controls">
            <button class="btn" id="calibrateBtn" onclick="calibrateSensors()">Calibrate</button>
            <button class="btn secondary" id="saveBtn" onclick="saveMeasurement()">Save Reading</button>
            <button class="btn secondary" id="resetBtn" onclick="resetReadings()">Reset</button>
        </div>
        
        <!-- Measurement History -->
        <div class="history-container">
            <div class="history-header">Recent Measurements</div>
            <div id="historyEntries">
                <div class="history-entry">
                    <span>No measurements saved yet</span>
                    <span class="history-time">--:--</span>
                </div>
            </div>
        </div>
        
        <!-- Sensor Status -->
        <div class="sensor-status">
            <div class="history-header">Sensor Status</div>
            <div class="sensor-info">
                <span class="sensor-label">Accelerometer:</span>
                <span class="sensor-value" id="accelStatus">Initializing...</span>
            </div>
            <div class="sensor-info">
                <span class="sensor-label">Gyroscope:</span>
                <span class="sensor-value" id="gyroStatus">Initializing...</span>
            </div>
            <div class="sensor-info">
                <span class="sensor-label">Magnetometer:</span>
                <span class="sensor-value" id="magnetStatus">Initializing...</span>
            </div>
            <div class="sensor-info">
                <span class="sensor-label">Orientation:</span>
                <span class="sensor-value" id="orientationStatus">Initializing...</span>
            </div>
        </div>
    </div>

    <script>
        // ES5 Compatible JavaScript for BlackBerry Passport
        
        // Global state
        var isCalibrated = false;
        var calibrationOffset = { pitch: 0, roll: 0, heading: 0 };
        var currentReadings = { pitch: 0, roll: 0, elevation: 0, heading: 0 };
        var measurementHistory = [];
        var sensorData = {
            accel: { x: 0, y: 0, z: 0 },
            gyro: { x: 0, y: 0, z: 0 },
            magnet: { x: 0, y: 0, z: 0 }
        };
        var lastUpdateTime = 0;
        var smoothingFactor = 0.8; // For sensor smoothing
        
        // Initialize app
        function initApp() {
            console.log('Initializing BlackBerry Passport Level & Elevation App...');
            
            // Initialize sensors
            initializeSensors();
            
            // Load saved measurements
            loadMeasurementHistory();
            
            // Set up periodic updates
            setInterval(updateDisplay, 50); // 20 FPS for smooth animation
            setInterval(savePersistentData, 30000); // Save every 30 seconds
            
            console.log('Level & Elevation App initialized successfully');
        }
        
        // Initialize device sensors
        function initializeSensors() {
            // Check for DeviceMotionEvent support
            if (window.DeviceMotionEvent) {
                console.log('DeviceMotion API supported');
                document.getElementById('accelStatus').textContent = 'Available';
                document.getElementById('gyroStatus').textContent = 'Available';
                
                // Request permission for iOS 13+ (if needed)
                if (typeof DeviceMotionEvent.requestPermission === 'function') {
                    DeviceMotionEvent.requestPermission()
                        .then(function(response) {
                            if (response === 'granted') {
                                setupMotionListeners();
                            } else {
                                showError('Motion sensor permission denied');
                            }
                        })
                        .catch(function(error) {
                            console.error('Permission request failed:', error);
                            setupMotionListeners(); // Try anyway
                        });
                } else {
                    setupMotionListeners();
                }
            } else {
                console.warn('DeviceMotion API not supported');
                document.getElementById('accelStatus').textContent = 'Not Available';
                document.getElementById('gyroStatus').textContent = 'Not Available';
                showError('Device motion sensors not available');
            }
            
            // Check for DeviceOrientationEvent support (compass)
            if (window.DeviceOrientationEvent) {
                console.log('DeviceOrientation API supported');
                document.getElementById('orientationStatus').textContent = 'Available';
                
                // Request permission for iOS 13+ (if needed)
                if (typeof DeviceOrientationEvent.requestPermission === 'function') {
                    DeviceOrientationEvent.requestPermission()
                        .then(function(response) {
                            if (response === 'granted') {
                                setupOrientationListeners();
                            } else {
                                console.warn('Orientation permission denied');
                            }
                        })
                        .catch(function(error) {
                            console.error('Orientation permission request failed:', error);
                            setupOrientationListeners(); // Try anyway
                        });
                } else {
                    setupOrientationListeners();
                }
            } else {
                console.warn('DeviceOrientation API not supported');
                document.getElementById('orientationStatus').textContent = 'Not Available';
                document.getElementById('magnetStatus').textContent = 'Not Available';
            }
        }
        
        // Set up motion event listeners
        function setupMotionListeners() {
            window.addEventListener('devicemotion', function(event) {
                var currentTime = Date.now();
                
                // Get accelerometer data
                var acceleration = event.accelerationIncludingGravity;
                if (acceleration) {
                    // Apply smoothing filter
                    sensorData.accel.x = smoothingFactor * sensorData.accel.x + (1 - smoothingFactor) * (acceleration.x || 0);
                    sensorData.accel.y = smoothingFactor * sensorData.accel.y + (1 - smoothingFactor) * (acceleration.y || 0);
                    sensorData.accel.z = smoothingFactor * sensorData.accel.z + (1 - smoothingFactor) * (acceleration.z || 0);
                    
                    // Calculate pitch and roll from accelerometer
                    calculateLevelFromAccel();
                }
                
                // Get gyroscope data
                var rotationRate = event.rotationRate;
                if (rotationRate) {
                    sensorData.gyro.x = rotationRate.alpha || 0;
                    sensorData.gyro.y = rotationRate.beta || 0;
                    sensorData.gyro.z = rotationRate.gamma || 0;
                }
                
                lastUpdateTime = currentTime;
            }, false);
            
            console.log('Motion listeners set up successfully');
        }
        
        // Set up orientation event listeners (compass)
        function setupOrientationListeners() {
            window.addEventListener('deviceorientation', function(event) {
                if (event.alpha !== null) {
                    // Compass heading (0-360 degrees)
                    var heading = event.alpha;
                    
                    // Apply smoothing
                    if (currentReadings.heading === 0) {
                        currentReadings.heading = heading;
                    } else {
                        // Handle 360/0 degree wraparound
                        var diff = heading - currentReadings.heading;
                        if (diff > 180) diff -= 360;
                        if (diff < -180) diff += 360;
                        currentReadings.heading += diff * (1 - smoothingFactor);
                        
                        // Normalize to 0-360
                        if (currentReadings.heading < 0) currentReadings.heading += 360;
                        if (currentReadings.heading >= 360) currentReadings.heading -= 360;
                    }
                    
                    document.getElementById('magnetStatus').textContent = 'Active';
                } else {
                    document.getElementById('magnetStatus').textContent = 'No Data';
                }
            }, false);
            
            console.log('Orientation listeners set up successfully');
        }
        
        // Calculate level readings from accelerometer data
        function calculateLevelFromAccel() {
            var ax = sensorData.accel.x;
            var ay = sensorData.accel.y;
            var az = sensorData.accel.z;
            
            // Calculate pitch (rotation around X-axis) - forward/backward tilt
            var pitch = Math.atan2(ay, Math.sqrt(ax * ax + az * az)) * (180 / Math.PI);
            
            // Calculate roll (rotation around Y-axis) - left/right tilt
            var roll = Math.atan2(-ax, Math.sqrt(ay * ay + az * az)) * (180 / Math.PI);
            
            // Calculate elevation angle (device tilt from horizontal)
            var elevation = Math.atan2(Math.sqrt(ax * ax + ay * ay), az) * (180 / Math.PI) - 90;
            
            // Apply calibration offset
            currentReadings.pitch = pitch - calibrationOffset.pitch;
            currentReadings.roll = roll - calibrationOffset.roll;
            currentReadings.elevation = elevation;
            
            // Update sensor status
            var magnitude = Math.sqrt(ax * ax + ay * ay + az * az);
            document.getElementById('accelStatus').textContent = 'Active (' + magnitude.toFixed(1) + ' m/s²)';
        }
        
        // Update display elements
        function updateDisplay() {
            // Update reading values
            document.getElementById('pitchValue').textContent = currentReadings.pitch.toFixed(1) + '°';
            document.getElementById('rollValue').textContent = currentReadings.roll.toFixed(1) + '°';
            document.getElementById('elevationValue').textContent = currentReadings.elevation.toFixed(1) + '°';
            document.getElementById('compassHeading').textContent = Math.round(currentReadings.heading) + '°';
            
            // Update level bubble position
            updateLevelBubble();
            
            // Update compass needle
            updateCompassNeedle();
            
            // Update level status
            updateLevelStatus();
            
            // Update accuracy indicator
            updateAccuracyIndicator();
        }
        
        // Update level bubble position
        function updateLevelBubble() {
            var bubble = document.getElementById('levelBubble');
            var display = document.getElementById('levelDisplay');
            
            // Calculate bubble position based on tilt
            var maxOffset = 120; // Maximum pixels from center
            var pitchOffset = (currentReadings.pitch / 45) * maxOffset; // 45 degrees = max offset
            var rollOffset = (currentReadings.roll / 45) * maxOffset;
            
            // Limit to circle bounds
            var distance = Math.sqrt(pitchOffset * pitchOffset + rollOffset * rollOffset);
            if (distance > maxOffset) {
                pitchOffset = (pitchOffset / distance) * maxOffset;
                rollOffset = (rollOffset / distance) * maxOffset;
            }
            
            // Apply transform
            bubble.style.transform = 'translate(' + 
                (rollOffset - 10) + 'px, ' + 
                (pitchOffset - 10) + 'px)';
            
            // Change bubble color based on level accuracy
            var levelAccuracy = Math.sqrt(currentReadings.pitch * currentReadings.pitch + currentReadings.roll * currentReadings.roll);
            if (levelAccuracy < 1) {
                bubble.style.backgroundColor = '#4CAF50'; // Green - very level
            } else if (levelAccuracy < 3) {
                bubble.style.backgroundColor = '#ff9800'; // Orange - somewhat level
            } else {
                bubble.style.backgroundColor = '#f44336'; // Red - not level
            }
        }
        
        // Update compass needle
        function updateCompassNeedle() {
            var needle = document.getElementById('compassNeedle');
            var adjustedHeading = currentReadings.heading - calibrationOffset.heading;
            
            // Normalize heading
            if (adjustedHeading < 0) adjustedHeading += 360;
            if (adjustedHeading >= 360) adjustedHeading -= 360;
            
            needle.style.transform = 'translate(-50%, -100%) rotate(' + adjustedHeading + 'deg)';
        }
        
        // Update level status text
        function updateLevelStatus() {
            var statusElement = document.getElementById('levelStatus');
            var levelAccuracy = Math.sqrt(currentReadings.pitch * currentReadings.pitch + currentReadings.roll * currentReadings.roll);
            
            if (levelAccuracy < 0.5) {
                statusElement.textContent = 'PERFECTLY LEVEL';
                statusElement.className = 'level-status level';
            } else if (levelAccuracy < 1.0) {
                statusElement.textContent = 'VERY LEVEL (' + levelAccuracy.toFixed(1) + '°)';
                statusElement.className = 'level-status level';
            } else if (levelAccuracy < 3.0) {
                statusElement.textContent = 'SLIGHTLY TILTED (' + levelAccuracy.toFixed(1) + '°)';
                statusElement.className = 'level-status tilted';
            } else {
                statusElement.textContent = 'NOT LEVEL (' + levelAccuracy.toFixed(1) + '°)';
                statusElement.className = 'level-status';
            }
        }
        
        // Update accuracy indicator
        function updateAccuracyIndicator() {
            var timeSinceUpdate = Date.now() - lastUpdateTime;
            var accuracy = 'High';
            
            if (timeSinceUpdate > 1000) {
                accuracy = 'No Data';
            } else if (timeSinceUpdate > 200) {
                accuracy = 'Low';
            } else if (timeSinceUpdate > 100) {
                accuracy = 'Medium';
            }
            
            document.getElementById('accuracyValue').textContent = accuracy;
        }
        
        // Calibrate sensors
        function calibrateSensors() {
            // Set current readings as zero reference
            calibrationOffset.pitch = currentReadings.pitch + calibrationOffset.pitch;
            calibrationOffset.roll = currentReadings.roll + calibrationOffset.roll;
            calibrationOffset.heading = currentReadings.heading;
            
            isCalibrated = true;
            document.getElementById('calibrationStatus').className = 'calibration-status calibrated';
            
            showSuccess('Sensors calibrated successfully');
            console.log('Sensors calibrated:', calibrationOffset);
        }
        
        // Save current measurement
        function saveMeasurement() {
            var measurement = {
                timestamp: new Date().toISOString(),
                pitch: currentReadings.pitch,
                roll: currentReadings.roll,
                elevation: currentReadings.elevation,
                heading: currentReadings.heading
            };
            
            // Add to history
            measurementHistory.unshift(measurement);
            
            // Keep only last 10 measurements
            if (measurementHistory.length > 10) {
                measurementHistory = measurementHistory.slice(0, 10);
            }
            
            // Update display
            updateHistoryDisplay();
            
            // Save to server
            saveMeasurementToServer(measurement);
            
            showSuccess('Measurement saved');
        }
        
        // Reset all readings and calibration
        function resetReadings() {
            calibrationOffset = { pitch: 0, roll: 0, heading: 0 };
            isCalibrated = false;
            document.getElementById('calibrationStatus').className = 'calibration-status';
            
            showSuccess('Readings reset');
        }
        
        // Update measurement history display
        function updateHistoryDisplay() {
            var container = document.getElementById('historyEntries');
            
            if (measurementHistory.length === 0) {
                container.innerHTML = '<div class="history-entry"><span>No measurements saved yet</span><span class="history-time">--:--</span></div>';
                return;
            }
            
            var html = '';
            for (var i = 0; i < measurementHistory.length; i++) {
                var measurement = measurementHistory[i];
                var time = new Date(measurement.timestamp);
                var timeStr = time.getHours().toString().padStart(2, '0') + ':' + 
                             time.getMinutes().toString().padStart(2, '0');
                
                html += '<div class="history-entry">' +
                       '<span>P:' + measurement.pitch.toFixed(1) + '° R:' + measurement.roll.toFixed(1) + '° H:' + Math.round(measurement.heading) + '°</span>' +
                       '<span class="history-time">' + timeStr + '</span>' +
                       '</div>';
            }
            
            container.innerHTML = html;
        }
        
        // Load measurement history from server
        function loadMeasurementHistory() {
            var xhr = new XMLHttpRequest();
            xhr.open('GET', '/api/measurements', true);
            xhr.onreadystatechange = function() {
                if (xhr.readyState === 4) {
                    if (xhr.status === 200) {
                        try {
                            var data = JSON.parse(xhr.responseText);
                            measurementHistory = data.measurements || [];
                            updateHistoryDisplay();
                        } catch (e) {
                            console.error('Error parsing measurement history:', e);
                        }
                    }
                }
            };
            xhr.send();
        }
        
        // Save measurement to server
        function saveMeasurementToServer(measurement) {
            var xhr = new XMLHttpRequest();
            xhr.open('POST', '/api/save-measurement', true);
            xhr.setRequestHeader('Content-Type', 'application/json');
            xhr.onreadystatechange = function() {
                if (xhr.readyState === 4) {
                    if (xhr.status === 200) {
                        console.log('Measurement saved to server');
                    } else {
                        console.error('Failed to save measurement to server');
                    }
                }
            };
            xhr.send(JSON.stringify(measurement));
        }
        
        // Save persistent data
        function savePersistentData() {
            // Save calibration and settings to localStorage
            try {
                localStorage.setItem('levelApp_calibration', JSON.stringify(calibrationOffset));
                localStorage.setItem('levelApp_isCalibrated', JSON.stringify(isCalibrated));
            } catch (e) {
                console.warn('Could not save to localStorage:', e);
            }
        }
        
        // Load persistent data
        function loadPersistentData() {
            try {
                var savedCalibration = localStorage.getItem('levelApp_calibration');
                var savedIsCalibrated = localStorage.getItem('levelApp_isCalibrated');
                
                if (savedCalibration) {
                    calibrationOffset = JSON.parse(savedCalibration);
                }
                
                if (savedIsCalibrated) {
                    isCalibrated = JSON.parse(savedIsCalibrated);
                    if (isCalibrated) {
                        document.getElementById('calibrationStatus').className = 'calibration-status calibrated';
                    }
                }
            } catch (e) {
                console.warn('Could not load from localStorage:', e);
            }
        }
        
        // Utility functions
        function showError(message) {
            var errorDiv = document.createElement('div');
            errorDiv.className = 'error-message';
            errorDiv.textContent = message;
            document.querySelector('.content').insertBefore(errorDiv, document.querySelector('.level-container'));
            
            setTimeout(function() {
                if (errorDiv.parentNode) {
                    errorDiv.parentNode.removeChild(errorDiv);
                }
            }, 5000);
        }
        
        function showSuccess(message) {
            var successDiv = document.createElement('div');
            successDiv.className = 'success-message';
            successDiv.textContent = message;
            document.querySelector('.content').insertBefore(successDiv, document.querySelector('.level-container'));
            
            setTimeout(function() {
                if (successDiv.parentNode) {
                    successDiv.parentNode.removeChild(successDiv);
                }
            }, 3000);
        }
        
        // Initialize when page loads
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', function() {
                loadPersistentData();
                initApp();
            });
        } else {
            loadPersistentData();
            initApp();
        }
        
        // Handle page unload
        window.addEventListener('beforeunload', function() {
            savePersistentData();
        });
        
        // Handle page visibility changes
        document.addEventListener('visibilitychange', function() {
            if (!document.hidden) {
                // Page became visible, resume updates
                console.log('Page visible, resuming sensor updates');
            } else {
                // Page hidden, save data
                savePersistentData();
            }
        });
    </script>
</body>
</html>'''

class LevelAppHandler(http.server.BaseHTTPRequestHandler):
    """Level & Elevation App HTTP Handler optimized for BlackBerry Passport"""
    
    def log_message(self, format, *args):
        """Enable request logging"""
        print(f"[{time.strftime('%H:%M:%S')}] {format % args}")
    
    def do_GET(self):
        """Handle GET requests"""
        try:
            if self.path == '/':
                self.serve_html()
            elif self.path == '/api/measurements':
                self.handle_measurements_api()
            else:
                self.send_error(404, 'Not Found')
        except Exception as e:
            print(f"GET request error: {e}")
            self.send_error(500, 'Internal Server Error')
    
    def do_POST(self):
        """Handle POST requests"""
        try:
            if self.path == '/api/save-measurement':
                self.handle_save_measurement_api()
            else:
                self.send_error(404, 'Not Found')
        except Exception as e:
            print(f"POST request error: {e}")
            self.send_error(500, 'Internal Server Error')
    
    def serve_html(self):
        """Serve the main HTML page"""
        try:
            self.send_response(200)
            self.send_header('Content-Type', 'text/html; charset=utf-8')
            self.send_header('Cache-Control', 'no-cache, no-store, must-revalidate')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Expires', '0')
            self.end_headers()
            self.wfile.write(HTML_CONTENT.encode('utf-8'))
        except Exception as e:
            print(f"Error serving HTML: {e}")
            self.send_error(500, 'Error loading page')
    
    def send_json(self, data, status_code=200):
        """Send JSON response"""
        try:
            self.send_response(status_code)
            self.send_header('Content-Type', 'application/json; charset=utf-8')
            self.send_header('Cache-Control', 'no-cache, no-store, must-revalidate')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Expires', '0')
            self.end_headers()
            
            json_str = json.dumps(data, separators=(',', ':'), ensure_ascii=False)
            self.wfile.write(json_str.encode('utf-8'))
        except Exception as e:
            print(f"Error sending JSON: {e}")
            self.send_error(500, 'JSON encoding error')
    
    def handle_measurements_api(self):
        """Handle measurements API request"""
        try:
            conn = sqlite3.connect(DB_PATH)
            cursor = conn.cursor()
            
            cursor.execute('''
                SELECT timestamp, pitch, roll, elevation, compass_heading, location_name, notes
                FROM measurements 
                ORDER BY timestamp DESC 
                LIMIT 10
            ''')
            
            results = cursor.fetchall()
            conn.close()
            
            measurements = []
            for result in results:
                measurements.append({
                    'timestamp': result[0],
                    'pitch': result[1],
                    'roll': result[2],
                    'elevation': result[3],
                    'heading': result[4],
                    'location': result[5],
                    'notes': result[6]
                })
            
            self.send_json({'measurements': measurements})
        except Exception as e:
            print(f"Error handling measurements API: {e}")
            self.send_json({'error': 'Failed to load measurements'}, 500)
    
    def handle_save_measurement_api(self):
        """Handle save measurement API request"""
        try:
            content_length = int(self.headers.get('Content-Length', 0))
            post_data = self.rfile.read(content_length)
            data = json.loads(post_data.decode('utf-8'))
            
            conn = sqlite3.connect(DB_PATH)
            cursor = conn.cursor()
            
            cursor.execute('''
                INSERT INTO measurements 
                (timestamp, pitch, roll, elevation, compass_heading, location_name, notes)
                VALUES (?, ?, ?, ?, ?, ?, ?)
            ''', (
                data.get('timestamp'),
                data.get('pitch', 0),
                data.get('roll', 0),
                data.get('elevation', 0),
                data.get('heading', 0),
                data.get('location', ''),
                data.get('notes', '')
            ))
            
            conn.commit()
            conn.close()
            
            self.send_json({'status': 'success', 'message': 'Measurement saved'})
        except Exception as e:
            print(f"Error saving measurement: {e}")
            self.send_json({'status': 'error', 'message': 'Failed to save measurement'}, 500)

class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    """Threaded TCP Server for BlackBerry Passport applications"""
    allow_reuse_address = True
    daemon_threads = True
    timeout = 30

def run_server(port=PORT):
    """Run the Level & Elevation App server"""
    try:
        # Initialize database
        init_database()
        
        print("=" * 60)
        print("BlackBerry Passport Level & Elevation App")
        print("=" * 60)
        print(f"Port: {port}")
        print(f"Database: {DB_PATH}")
        print(f"Base Directory: {BASE_DIR}")
        print("")
        print("Features:")
        print("- Digital level with bubble display")
        print("- Pitch and roll measurements")
        print("- Digital compass")
        print("- Elevation angle calculation")
        print("- Sensor calibration")
        print("- Measurement history")
        print("- ES5 compatible JavaScript")
        print("- BlackBerry Passport optimized UI")
        print("")
        print(f"🚀 Starting server on http://localhost:{port}")
        print("📱 Optimized for BlackBerry Passport")
        print("📐 Ready to level your world!")
        print("⏹️  Press Ctrl+C to stop")
        print("=" * 60)
        
        with ThreadedTCPServer(("", port), LevelAppHandler) as httpd:
            httpd.serve_forever()
            
    except KeyboardInterrupt:
        print("\n" + "=" * 60)
        print("👋 Shutting down Level & Elevation App")
        print("=" * 60)
    except Exception as e:
        print(f"❌ Server error: {e}")
        sys.exit(1)

if __name__ == "__main__":
    run_server()
