#!/usr/bin/env python3
"""
BlackBerry Passport Multi-Sensor Dashboard
A comprehensive sensor monitoring app that utilizes all available sensors:
- Accelerometer & Gyroscope (motion)
- Magnetometer (compass)
- Proximity sensor
- Ambient light sensor
- Device orientation
- Battery status
- Network information
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 = 8028
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DB_PATH = os.path.join(BASE_DIR, 'sensor_data.db')

# Initialize database for storing sensor readings
def init_database():
    """Initialize SQLite database for storing sensor data"""
    conn = sqlite3.connect(DB_PATH)
    cursor = conn.cursor()
    
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS sensor_readings (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            sensor_type TEXT,
            x_value REAL,
            y_value REAL,
            z_value REAL,
            magnitude REAL,
            additional_data TEXT
        )
    ''')
    
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS environmental_data (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            light_level REAL,
            proximity_distance REAL,
            battery_level INTEGER,
            battery_charging BOOLEAN,
            network_type TEXT,
            device_orientation 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>Sensor Dashboard - 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: 13px;
            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: 12px 15px;
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            z-index: 1000;
            display: flex;
            justify-content: space-between;
            align-items: center;
            height: 45px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.3);
        }
        
        .header h1 {
            margin: 0;
            font-size: 16px;
            font-weight: normal;
            flex: 1;
            text-align: center;
        }
        
        .recording-status {
            width: 10px;
            height: 10px;
            border-radius: 50%;
            background-color: #666;
            margin-right: 10px;
        }
        
        .recording-status.recording {
            background-color: #f44336;
            animation: blink 1s infinite;
        }
        
        @keyframes blink {
            0%, 50% { opacity: 1; }
            51%, 100% { opacity: 0.3; }
        }
        
        .content {
            padding: 65px 10px 20px 10px;
            min-height: calc(100vh - 85px);
        }
        
        /* Sensor Grid Layout */
        .sensor-grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 10px;
            margin-bottom: 15px;
        }
        
        .sensor-card {
            background-color: #2b2b2b;
            border: 1px solid #444;
            border-radius: 8px;
            padding: 12px;
            min-height: 120px;
            position: relative;
        }
        
        .sensor-card.active {
            border-color: #00769e;
            box-shadow: 0 0 8px rgba(0, 118, 158, 0.3);
        }
        
        .sensor-title {
            font-size: 12px;
            font-weight: bold;
            color: #00769e;
            margin-bottom: 8px;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        
        .sensor-status {
            font-size: 10px;
            padding: 2px 6px;
            border-radius: 3px;
            background-color: #666;
        }
        
        .sensor-status.active {
            background-color: #4CAF50;
        }
        
        .sensor-status.error {
            background-color: #f44336;
        }
        
        .sensor-values {
            font-family: monospace;
            font-size: 11px;
            line-height: 1.4;
        }
        
        .sensor-value-row {
            display: flex;
            justify-content: space-between;
            margin-bottom: 3px;
        }
        
        .sensor-label {
            color: #aaa;
        }
        
        .sensor-data {
            color: #00769e;
            font-weight: bold;
        }
        
        /* Motion Visualization */
        .motion-viz {
            background-color: #2b2b2b;
            border: 1px solid #444;
            border-radius: 8px;
            padding: 15px;
            margin-bottom: 15px;
            text-align: center;
        }
        
        .motion-sphere {
            width: 120px;
            height: 120px;
            border: 2px solid #00769e;
            border-radius: 50%;
            margin: 0 auto 10px auto;
            position: relative;
            background: radial-gradient(circle at 30% 30%, #333, #1e1e1e);
        }
        
        .motion-dot {
            position: absolute;
            width: 8px;
            height: 8px;
            background-color: #4CAF50;
            border-radius: 50%;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            transition: all 0.1s ease;
            box-shadow: 0 0 6px rgba(76, 175, 80, 0.6);
        }
        
        .motion-axes {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
        }
        
        .motion-axes::before,
        .motion-axes::after {
            content: '';
            position: absolute;
            background-color: rgba(0, 118, 158, 0.3);
        }
        
        .motion-axes::before {
            width: 1px;
            height: 100%;
            left: 50%;
            top: 0;
        }
        
        .motion-axes::after {
            width: 100%;
            height: 1px;
            top: 50%;
            left: 0;
        }
        
        /* Environmental Sensors */
        .env-sensors {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 10px;
            margin-bottom: 15px;
        }
        
        .env-card {
            background-color: #2b2b2b;
            border: 1px solid #444;
            border-radius: 8px;
            padding: 12px;
            text-align: center;
        }
        
        .env-value {
            font-size: 20px;
            font-weight: bold;
            color: #00769e;
            margin: 8px 0;
        }
        
        .env-status {
            font-size: 12px;
            color: #666;
            margin: 2px 0;
            font-style: italic;
        }
        
        .env-label {
            font-size: 11px;
            color: #aaa;
        }
        
        .env-bar {
            width: 100%;
            height: 6px;
            background-color: #444;
            border-radius: 3px;
            margin: 8px 0;
            overflow: hidden;
        }
        
        .env-bar-fill {
            height: 100%;
            background: linear-gradient(90deg, #00769e, #0099cc);
            border-radius: 3px;
            width: 0%;
            transition: width 0.3s ease;
        }
        
        /* Controls */
        .controls {
            display: flex;
            gap: 8px;
            margin-bottom: 15px;
        }
        
        .btn {
            flex: 1;
            padding: 10px;
            background-color: #00769e;
            color: white;
            border: none;
            border-radius: 5px;
            font-size: 12px;
            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;
        }
        
        /* Data Log */
        .data-log {
            background-color: #2b2b2b;
            border: 1px solid #444;
            border-radius: 8px;
            padding: 12px;
            margin-bottom: 15px;
        }
        
        .log-header {
            font-size: 14px;
            font-weight: bold;
            margin-bottom: 10px;
            color: #00769e;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        
        .log-entries {
            max-height: 150px;
            overflow-y: auto;
            font-family: monospace;
            font-size: 10px;
            line-height: 1.3;
        }
        
        .log-entry {
            padding: 2px 0;
            border-bottom: 1px solid #333;
        }
        
        .log-entry:last-child {
            border-bottom: none;
        }
        
        .log-time {
            color: #888;
        }
        
        .log-sensor {
            color: #00769e;
        }
        
        .log-value {
            color: #ccc;
        }
        
        /* Device Info */
        .device-info {
            background-color: #2b2b2b;
            border: 1px solid #444;
            border-radius: 8px;
            padding: 12px;
        }
        
        .device-info-grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 8px;
        }
        
        .device-info-item {
            display: flex;
            justify-content: space-between;
            font-size: 11px;
            padding: 4px 0;
        }
        
        .device-info-label {
            color: #aaa;
        }
        
        .device-info-value {
            color: #00769e;
            font-weight: bold;
        }
        
        /* Responsive adjustments */
        @media (max-width: 480px) {
            .sensor-grid {
                grid-template-columns: 1fr;
            }
            
            .env-sensors {
                grid-template-columns: 1fr;
            }
            
            .controls {
                flex-direction: column;
            }
        }
        
        /* Landscape mode optimizations */
        @media (orientation: landscape) {
            .content {
                padding: 60px 8px 8px 8px;
            }
            
            .sensor-grid {
                grid-template-columns: repeat(3, 1fr);
            }
            
            .env-sensors {
                grid-template-columns: repeat(4, 1fr);
            }
        }
        
        .error-message {
            background-color: #f44336;
            color: white;
            padding: 8px;
            border-radius: 4px;
            margin: 8px 0;
            text-align: center;
            font-size: 12px;
        }
        
        .success-message {
            background-color: #4CAF50;
            color: white;
            padding: 8px;
            border-radius: 4px;
            margin: 8px 0;
            text-align: center;
            font-size: 12px;
        }
    </style>
</head>
<body>
    <div class="header">
        <h1>Sensor Dashboard</h1>
        <div class="recording-status" id="recordingStatus"></div>
    </div>
    
    <div class="content">
        <!-- Motion Visualization -->
        <div class="motion-viz">
            <div class="motion-sphere" id="motionSphere">
                <div class="motion-axes"></div>
                <div class="motion-dot" id="motionDot"></div>
            </div>
            <div style="font-size: 12px; color: #aaa;">Motion Visualization</div>
        </div>
        
        <!-- Sensor Grid -->
        <div class="sensor-grid">
            <!-- Accelerometer -->
            <div class="sensor-card" id="accelCard">
                <div class="sensor-title">
                    Accelerometer
                    <span class="sensor-status" id="accelStatus">Inactive</span>
                </div>
                <div class="sensor-values" id="accelValues">
                    <div class="sensor-value-row">
                        <span class="sensor-label">X:</span>
                        <span class="sensor-data" id="accelX">0.00</span>
                    </div>
                    <div class="sensor-value-row">
                        <span class="sensor-label">Y:</span>
                        <span class="sensor-data" id="accelY">0.00</span>
                    </div>
                    <div class="sensor-value-row">
                        <span class="sensor-label">Z:</span>
                        <span class="sensor-data" id="accelZ">0.00</span>
                    </div>
                    <div class="sensor-value-row">
                        <span class="sensor-label">Mag:</span>
                        <span class="sensor-data" id="accelMag">0.00</span>
                    </div>
                </div>
            </div>
            
            <!-- Gyroscope -->
            <div class="sensor-card" id="gyroCard">
                <div class="sensor-title">
                    Gyroscope
                    <span class="sensor-status" id="gyroStatus">Inactive</span>
                </div>
                <div class="sensor-values" id="gyroValues">
                    <div class="sensor-value-row">
                        <span class="sensor-label">α:</span>
                        <span class="sensor-data" id="gyroAlpha">0.00</span>
                    </div>
                    <div class="sensor-value-row">
                        <span class="sensor-label">β:</span>
                        <span class="sensor-data" id="gyroBeta">0.00</span>
                    </div>
                    <div class="sensor-value-row">
                        <span class="sensor-label">γ:</span>
                        <span class="sensor-data" id="gyroGamma">0.00</span>
                    </div>
                    <div class="sensor-value-row">
                        <span class="sensor-label">Rate:</span>
                        <span class="sensor-data" id="gyroRate">0.00</span>
                    </div>
                </div>
            </div>
            
            <!-- Magnetometer -->
            <div class="sensor-card" id="magnetCard">
                <div class="sensor-title">
                    Magnetometer
                    <span class="sensor-status" id="magnetStatus">Inactive</span>
                </div>
                <div class="sensor-values" id="magnetValues">
                    <div class="sensor-value-row">
                        <span class="sensor-label">Heading:</span>
                        <span class="sensor-data" id="magnetHeading">0°</span>
                    </div>
                    <div class="sensor-value-row">
                        <span class="sensor-label">Accuracy:</span>
                        <span class="sensor-data" id="magnetAccuracy">Unknown</span>
                    </div>
                    <div class="sensor-value-row">
                        <span class="sensor-label">Direction:</span>
                        <span class="sensor-data" id="magnetDirection">N</span>
                    </div>
                </div>
            </div>
            
            <!-- Orientation -->
            <div class="sensor-card" id="orientCard">
                <div class="sensor-title">
                    Orientation
                    <span class="sensor-status" id="orientStatus">Inactive</span>
                </div>
                <div class="sensor-values" id="orientValues">
                    <div class="sensor-value-row">
                        <span class="sensor-label">Mode:</span>
                        <span class="sensor-data" id="orientMode">Portrait</span>
                    </div>
                    <div class="sensor-value-row">
                        <span class="sensor-label">Angle:</span>
                        <span class="sensor-data" id="orientAngle">0°</span>
                    </div>
                    <div class="sensor-value-row">
                        <span class="sensor-label">Lock:</span>
                        <span class="sensor-data" id="orientLock">No</span>
                    </div>
                </div>
            </div>
        </div>
        
        <!-- Environmental Sensors -->
        <div class="env-sensors">
            <!-- Ambient Light -->
            <div class="env-card" id="lightCard">
                <div class="env-label">Ambient Light</div>
                <div class="env-value" id="lightValue">-- lux</div>
                <div class="env-status" id="lightMethodStatus">Detecting...</div>
                <div class="env-bar">
                    <div class="env-bar-fill" id="lightBar"></div>
                </div>
            </div>
            
            <!-- Proximity -->
            <div class="env-card" id="proximityCard">
                <div class="env-label">Proximity</div>
                <div class="env-value" id="proximityValue">-- cm</div>
                <div class="env-status" id="proximityMethodStatus">Detecting...</div>
                <div class="env-bar">
                    <div class="env-bar-fill" id="proximityBar"></div>
                </div>
            </div>
            
            <!-- Battery -->
            <div class="env-card" id="batteryCard">
                <div class="env-label">Battery</div>
                <div class="env-value" id="batteryValue">--%</div>
                <div class="env-bar">
                    <div class="env-bar-fill" id="batteryBar"></div>
                </div>
            </div>
            
            <!-- Network -->
            <div class="env-card" id="networkCard">
                <div class="env-label">Network</div>
                <div class="env-value" id="networkValue">--</div>
                <div style="font-size: 10px; color: #888; margin-top: 5px;" id="networkInfo">Checking...</div>
            </div>
        </div>
        
        <!-- Controls -->
        <div class="controls">
            <button class="btn" id="startBtn" onclick="startRecording()">Start Recording</button>
            <button class="btn secondary" id="stopBtn" onclick="stopRecording()" disabled>Stop</button>
            <button class="btn secondary" id="clearBtn" onclick="clearLog()">Clear Log</button>
            <button class="btn secondary" id="exportBtn" onclick="exportData()">Export</button>
        </div>
        
        <!-- Sensor Test Controls -->
        <div class="controls">
            <button class="btn secondary" onclick="testLightSensor()">Test Light</button>
            <button class="btn secondary" onclick="testProximitySensor()">Test Proximity</button>
            <button class="btn secondary" onclick="requestPermissions()">Request Permissions</button>
            <button class="btn secondary" onclick="debugSensors()">Debug Info</button>
        </div>
        
        <!-- Data Log -->
        <div class="data-log">
            <div class="log-header">
                Sensor Data Log
                <span id="logCount">0 entries</span>
            </div>
            <div class="log-entries" id="logEntries">
                <div class="log-entry">
                    <span class="log-time">--:--:--</span> 
                    <span class="log-sensor">System</span> 
                    <span class="log-value">Waiting for sensor data...</span>
                </div>
            </div>
        </div>
        
        <!-- Device Info -->
        <div class="device-info">
            <div class="log-header">Device Information</div>
            <div class="device-info-grid">
                <div class="device-info-item">
                    <span class="device-info-label">User Agent:</span>
                    <span class="device-info-value" id="userAgent">--</span>
                </div>
                <div class="device-info-item">
                    <span class="device-info-label">Screen:</span>
                    <span class="device-info-value" id="screenInfo">--</span>
                </div>
                <div class="device-info-item">
                    <span class="device-info-label">Memory:</span>
                    <span class="device-info-value" id="memoryInfo">--</span>
                </div>
                <div class="device-info-item">
                    <span class="device-info-label">Connection:</span>
                    <span class="device-info-value" id="connectionInfo">--</span>
                </div>
                <div class="device-info-item">
                    <span class="device-info-label">Platform:</span>
                    <span class="device-info-value" id="platformInfo">--</span>
                </div>
                <div class="device-info-item">
                    <span class="device-info-label">Language:</span>
                    <span class="device-info-value" id="languageInfo">--</span>
                </div>
            </div>
        </div>
    </div>

    <script>
        // ES5 Compatible JavaScript for BlackBerry Passport
        
        // Global state
        var isRecording = false;
        var sensorData = {
            accelerometer: { x: 0, y: 0, z: 0, magnitude: 0 },
            gyroscope: { alpha: 0, beta: 0, gamma: 0, rate: 0 },
            magnetometer: { heading: 0, accuracy: 0 },
            orientation: { angle: 0, mode: 'portrait' },
            light: { level: 0 },
            proximity: { distance: 0 },
            battery: { level: 0, charging: false },
            network: { type: 'unknown', speed: 0 }
        };
        var dataLog = [];
        var maxLogEntries = 100;
        var updateInterval = null;
        
        // Initialize app
        function initApp() {
            console.log('Initializing BlackBerry Passport Sensor Dashboard...');
            
            // Debug: Check what APIs are available
            debugAvailableAPIs();
            
            // Initialize all sensors
            initializeMotionSensors();
            initializeOrientationSensors();
            initializeEnvironmentalSensors();
            initializeDeviceInfo();
            
            // Start periodic updates
            updateInterval = setInterval(updateDisplay, 100); // 10 FPS
            
            console.log('Sensor Dashboard initialized successfully');
        }
        
        // Debug function to check available APIs
        function debugAvailableAPIs() {
            console.log('=== API Availability Check ===');
            console.log('DeviceMotionEvent:', typeof DeviceMotionEvent !== 'undefined');
            console.log('DeviceOrientationEvent:', typeof DeviceOrientationEvent !== 'undefined');
            console.log('AmbientLightSensor:', typeof AmbientLightSensor !== 'undefined');
            console.log('ProximitySensor:', typeof ProximitySensor !== 'undefined');
            console.log('navigator.getBattery:', typeof navigator.getBattery === 'function');
            console.log('navigator.connection:', typeof navigator.connection !== 'undefined');
            console.log('navigator.permissions:', typeof navigator.permissions !== 'undefined');
            console.log('navigator.sensor:', typeof navigator.sensor !== 'undefined');
            console.log('window.sensor:', typeof window.sensor !== 'undefined');
            console.log('blackberry object:', typeof blackberry !== 'undefined');
            if (typeof blackberry !== 'undefined') {
                console.log('blackberry.sensors:', typeof blackberry.sensors !== 'undefined');
            }
            console.log('window.DeviceLightEvent:', typeof window.DeviceLightEvent !== 'undefined');
            console.log('window.DeviceProximityEvent:', typeof window.DeviceProximityEvent !== 'undefined');
            console.log('Blob support:', typeof Blob !== 'undefined');
            console.log('URL.createObjectURL:', typeof window.URL !== 'undefined' && typeof window.URL.createObjectURL === 'function');
            
            // Check for additional sensor-related objects
            console.log('=== Additional Sensor Objects ===');
            console.log('window.sensors:', typeof window.sensors !== 'undefined');
            console.log('navigator.sensors:', typeof navigator.sensors !== 'undefined');
            console.log('window.device:', typeof window.device !== 'undefined');
            console.log('navigator.device:', typeof navigator.device !== 'undefined');
            
            // Check for specific sensor properties
            if (typeof navigator !== 'undefined') {
                var navKeys = Object.keys(navigator);
                var sensorKeys = navKeys.filter(function(key) {
                    return key.toLowerCase().indexOf('sensor') !== -1 || 
                           key.toLowerCase().indexOf('light') !== -1 ||
                           key.toLowerCase().indexOf('proximity') !== -1;
                });
                if (sensorKeys.length > 0) {
                    console.log('Navigator sensor-related keys:', sensorKeys);
                }
            }
            
            console.log('==============================');
            console.log('');
            console.log('🔍 REALITY CHECK:');
            console.log('✅ BlackBerry Passport HAS ambient light & proximity hardware');
            console.log('❌ BB10 WebKit browser (2014) lacks modern sensor web APIs');
            console.log('💡 Using intelligent simulation for unsupported sensors');
            console.log('');
        }
        
        // Initialize motion sensors (accelerometer, gyroscope)
        function initializeMotionSensors() {
            if (window.DeviceMotionEvent) {
                console.log('DeviceMotion API supported');
                
                // 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';
            }
        }
        
        // Set up motion event listeners
        function setupMotionListeners() {
            window.addEventListener('devicemotion', function(event) {
                // Accelerometer data
                var acceleration = event.accelerationIncludingGravity;
                if (acceleration) {
                    sensorData.accelerometer.x = acceleration.x || 0;
                    sensorData.accelerometer.y = acceleration.y || 0;
                    sensorData.accelerometer.z = acceleration.z || 0;
                    sensorData.accelerometer.magnitude = Math.sqrt(
                        sensorData.accelerometer.x * sensorData.accelerometer.x +
                        sensorData.accelerometer.y * sensorData.accelerometer.y +
                        sensorData.accelerometer.z * sensorData.accelerometer.z
                    );
                    
                    document.getElementById('accelStatus').textContent = 'Active';
                    document.getElementById('accelCard').classList.add('active');
                    
                    if (isRecording) {
                        logSensorData('Accelerometer', sensorData.accelerometer);
                    }
                }
                
                // Gyroscope data
                var rotationRate = event.rotationRate;
                if (rotationRate) {
                    sensorData.gyroscope.alpha = rotationRate.alpha || 0;
                    sensorData.gyroscope.beta = rotationRate.beta || 0;
                    sensorData.gyroscope.gamma = rotationRate.gamma || 0;
                    sensorData.gyroscope.rate = Math.sqrt(
                        sensorData.gyroscope.alpha * sensorData.gyroscope.alpha +
                        sensorData.gyroscope.beta * sensorData.gyroscope.beta +
                        sensorData.gyroscope.gamma * sensorData.gyroscope.gamma
                    );
                    
                    document.getElementById('gyroStatus').textContent = 'Active';
                    document.getElementById('gyroCard').classList.add('active');
                    
                    if (isRecording) {
                        logSensorData('Gyroscope', sensorData.gyroscope);
                    }
                }
            }, false);
            
            console.log('Motion listeners set up successfully');
        }
        
        // Initialize orientation sensors (magnetometer, device orientation)
        function initializeOrientationSensors() {
            if (window.DeviceOrientationEvent) {
                console.log('DeviceOrientation API supported');
                
                // 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('magnetStatus').textContent = 'Not Available';
                document.getElementById('orientStatus').textContent = 'Not Available';
            }
        }
        
        // Set up orientation event listeners
        function setupOrientationListeners() {
            window.addEventListener('deviceorientation', function(event) {
                // Magnetometer (compass) data
                if (event.alpha !== null) {
                    sensorData.magnetometer.heading = event.alpha;
                    sensorData.magnetometer.accuracy = event.webkitCompassAccuracy || 0;
                    
                    document.getElementById('magnetStatus').textContent = 'Active';
                    document.getElementById('magnetCard').classList.add('active');
                    
                    if (isRecording) {
                        logSensorData('Magnetometer', sensorData.magnetometer);
                    }
                }
                
                // Device orientation
                if (event.beta !== null && event.gamma !== null) {
                    sensorData.orientation.angle = Math.round(event.beta);
                    
                    // Determine orientation mode
                    var absGamma = Math.abs(event.gamma);
                    var absBeta = Math.abs(event.beta);
                    
                    if (absGamma > absBeta) {
                        sensorData.orientation.mode = event.gamma > 0 ? 'landscape-left' : 'landscape-right';
                    } else {
                        sensorData.orientation.mode = event.beta > 0 ? 'portrait' : 'portrait-upside-down';
                    }
                    
                    document.getElementById('orientStatus').textContent = 'Active';
                    document.getElementById('orientCard').classList.add('active');
                    
                    if (isRecording) {
                        logSensorData('Orientation', sensorData.orientation);
                    }
                }
            }, false);
            
            console.log('Orientation listeners set up successfully');
        }
        
        // Initialize environmental sensors
        function initializeEnvironmentalSensors() {
            // Ambient Light Sensor - BlackBerry Passport has the hardware but BB10 WebKit doesn't support web APIs
            console.log('Checking ambient light sensor support...');
            console.log('Note: BlackBerry Passport HAS ambient light hardware, but BB10 WebKit browser lacks API support');
            
            var lightSensorInitialized = false;
            
            // Method 1: Modern AmbientLightSensor API
            if ('AmbientLightSensor' in window) {
                try {
                    console.log('Trying AmbientLightSensor API...');
                    navigator.permissions.query({name: 'ambient-light-sensor'}).then(function(result) {
                        console.log('Ambient light permission:', result.state);
                        if (result.state === 'granted' || result.state === 'prompt') {
                            var lightSensor = new AmbientLightSensor();
                            lightSensor.addEventListener('reading', function() {
                                sensorData.light.level = lightSensor.illuminance;
                                console.log('Light level:', lightSensor.illuminance);
                                if (isRecording) {
                                    logSensorData('Light', sensorData.light);
                                }
                            });
                            lightSensor.addEventListener('error', function(event) {
                                console.error('Light sensor error:', event.error);
                            });
                            lightSensor.start();
                            lightSensorInitialized = true;
                            console.log('AmbientLightSensor initialized successfully');
                        }
                    }).catch(function(error) {
                        console.warn('Permission query failed:', error);
                    });
                } catch (error) {
                    console.warn('AmbientLightSensor not available:', error);
                }
            }
            
            // Method 2: Legacy devicelight event (BlackBerry Passport likely uses this)
            if (!lightSensorInitialized && typeof window.addEventListener === 'function') {
                try {
                    console.log('Trying devicelight event...');
                    window.addEventListener('devicelight', function(event) {
                        console.log('Device light event received:', event.value, 'lux');
                        sensorData.light.level = event.value;
                        if (isRecording) {
                            logSensorData('Light', sensorData.light);
                        }
                    });
                    
                    // Try to trigger initial light reading
                    console.log('Attempting to trigger initial light sensor reading...');
                    
                    // Method 2a: Try to access sensor directly via navigator
                    if (navigator.sensor && navigator.sensor.light) {
                        try {
                            navigator.sensor.light.getCurrentReading(function(reading) {
                                console.log('Navigator sensor light reading:', reading);
                                sensorData.light.level = reading.value || reading.illuminance || 0;
                            });
                        } catch (e) {
                            console.log('Navigator sensor light failed:', e);
                        }
                    }
                    
                    // Method 2b: Check for window.sensor object
                    if (typeof window.sensor !== 'undefined' && window.sensor.light) {
                        try {
                            window.sensor.light.getCurrentReading(function(reading) {
                                console.log('Window sensor light reading:', reading);
                                sensorData.light.level = reading.value || reading.illuminance || 0;
                            });
                        } catch (e) {
                            console.log('Window sensor light failed:', e);
                        }
                    }
                    
                    lightSensorInitialized = true;
                    console.log('Device light event listener set up - waiting for light changes');
                } catch (error) {
                    console.warn('Device light event not available:', error);
                }
            }
            
            // Method 3: BlackBerry WebWorks API (if available)
            if (!lightSensorInitialized && typeof blackberry !== 'undefined' && blackberry.sensors) {
                try {
                    console.log('Trying BlackBerry WebWorks sensors...');
                    if (blackberry.sensors.setOptions) {
                        blackberry.sensors.setOptions('devicelight', {
                            delay: 1000,
                            background: true
                        });
                    }
                    if (blackberry.sensors.addEventListener) {
                        blackberry.sensors.addEventListener('devicelight', function(info) {
                            console.log('BlackBerry light sensor:', info);
                            sensorData.light.level = info.lightLevel || info.value || 0;
                            if (isRecording) {
                                logSensorData('Light', sensorData.light);
                            }
                        });
                        lightSensorInitialized = true;
                        console.log('BlackBerry WebWorks light sensor initialized');
                    }
                } catch (error) {
                    console.warn('BlackBerry WebWorks sensors not available:', error);
                }
            }
            
            // Method 4: Try alternative sensor activation approaches
            if (!lightSensorInitialized) {
                console.log('Trying alternative light sensor activation methods...');
                
                // Method 4a: Try to activate sensor via focus/blur events
                try {
                    window.addEventListener('focus', function() {
                        console.log('Window focus - checking for light sensor activation');
                        // Try to trigger a light reading
                        setTimeout(function() {
                            var event = new Event('devicelight');
                            event.value = Math.random() * 1000; // Random test value
                            window.dispatchEvent(event);
                        }, 100);
                    });
                    
                    window.addEventListener('blur', function() {
                        console.log('Window blur - checking for light sensor activation');
                    });
                } catch (e) {
                    console.log('Focus/blur light sensor activation failed:', e);
                }
                
                // Method 4b: Try to poll for sensor data periodically
                var lightPollingAttempts = 0;
                var lightPollingInterval = setInterval(function() {
                    lightPollingAttempts++;
                    
                    // Try different approaches to get light data
                    if (typeof navigator !== 'undefined') {
                        // Check for any new sensor properties that might have appeared
                        var navKeys = Object.keys(navigator);
                        var newSensorKeys = navKeys.filter(function(key) {
                            return key.toLowerCase().indexOf('light') !== -1 || 
                                   key.toLowerCase().indexOf('ambient') !== -1;
                        });
                        
                        if (newSensorKeys.length > 0) {
                            console.log('Found new light sensor keys during polling:', newSensorKeys);
                            newSensorKeys.forEach(function(key) {
                                try {
                                    if (typeof navigator[key] === 'function') {
                                        navigator[key](function(reading) {
                                            console.log('Polled light sensor reading from ' + key + ':', reading);
                                            sensorData.light.level = reading.value || reading.illuminance || reading;
                                        });
                                    }
                                } catch (e) {
                                    console.log('Failed to poll ' + key + ':', e);
                                }
                            });
                        }
                    }
                    
                    // Stop polling after 30 attempts (5 minutes)
                    if (lightPollingAttempts >= 30) {
                        clearInterval(lightPollingInterval);
                console.log('Light sensor polling stopped - BB10 WebKit lacks sensor API support');
                console.log('Starting intelligent light simulation based on device usage patterns');
                startIntelligentLightSimulation();
                    }
                }, 10000); // Poll every 10 seconds
                
                console.log('Light sensor polling started');
            }
            
            // Intelligent light simulation function (since BB10 WebKit lacks sensor API support)
            function startIntelligentLightSimulation() {
                console.log('BlackBerry Passport has ambient light hardware, but BB10 WebKit browser cannot access it');
                console.log('Using intelligent simulation based on time, interactions, and device orientation');
                
                // Update status to show why we're simulating
                setTimeout(function() {
                    var lightStatus = document.getElementById('lightMethodStatus');
                    if (lightStatus) {
                        lightStatus.textContent = 'Hardware present, API unsupported';
                        lightStatus.style.color = '#cc6600';
                    }
                }, 1000);
                
                var baseLight = 300; // Base light level
                var lastInteraction = Date.now();
                
                // Track user interactions and device orientation to simulate realistic light changes
                document.addEventListener('touchstart', function() {
                    lastInteraction = Date.now();
                    // Simulate screen brightness affecting ambient light reading
                    sensorData.light.level = Math.round(400 + Math.random() * 300); // Screen on = higher reading
                    console.log('Simulated light increase (screen active):', sensorData.light.level);
                });
                
                document.addEventListener('click', function() {
                    lastInteraction = Date.now();
                    sensorData.light.level = Math.round(350 + Math.random() * 400);
                    console.log('Simulated light change (user interaction):', sensorData.light.level);
                });
                
                // Use device orientation to simulate covering the sensor
                window.addEventListener('deviceorientation', function(event) {
                    // Simulate covering sensor when device is face down
                    if (Math.abs(event.beta) > 120) { // Device is roughly face down
                        sensorData.light.level = Math.round(5 + Math.random() * 15); // Very low light
                        console.log('Simulated light sensor covered (face down):', sensorData.light.level);
                    } else if (Math.abs(event.beta) < 30 && Math.abs(event.gamma) < 30) { // Device upright
                        var hour = new Date().getHours();
                        if (hour >= 8 && hour < 18) {
                            sensorData.light.level = Math.round(600 + Math.random() * 400); // Bright daylight
                        } else {
                            sensorData.light.level = Math.round(100 + Math.random() * 200); // Indoor lighting
                        }
                        console.log('Simulated normal light (device upright):', sensorData.light.level);
                    }
                });
                
                setInterval(function() {
                    var hour = new Date().getHours();
                    var timeSinceInteraction = Date.now() - lastInteraction;
                    
                    // Base light level by time of day
                    var timeBasedLight = 0;
                    if (hour >= 6 && hour < 8) {
                        timeBasedLight = 100 + (hour - 6) * 200; // Dawn: 100-500 lux
                    } else if (hour >= 8 && hour < 18) {
                        timeBasedLight = 500 + Math.random() * 300; // Day: 500-800 lux
                    } else if (hour >= 18 && hour < 20) {
                        timeBasedLight = 200 - (hour - 18) * 90; // Dusk: 200-20 lux
                    } else {
                        timeBasedLight = 5 + Math.random() * 15; // Night: 5-20 lux
                    }
                    
                    // Add interaction-based variation
                    if (timeSinceInteraction < 30000) { // Last 30 seconds
                        timeBasedLight += Math.random() * 100 - 50; // ±50 lux variation
                    }
                    
                    sensorData.light.level = Math.max(0, Math.round(timeBasedLight));
                    
                    if (isRecording) {
                        logSensorData('Light', { 
                            level: sensorData.light.level, 
                            simulated: true,
                            method: 'time_and_interaction'
                        });
                    }
                }, 3000); // Update every 3 seconds
                
                console.log('Simulated light sensor active with interaction detection');
            }
            
            // Proximity Sensor - Multiple approaches for BlackBerry Passport
            console.log('Initializing proximity sensor...');
            
            var proximitySensorInitialized = false;
            
            // Method 1: Modern ProximitySensor API
            if ('ProximitySensor' in window) {
                try {
                    console.log('Trying ProximitySensor API...');
                    var proximitySensor = new ProximitySensor();
                    proximitySensor.addEventListener('reading', function() {
                        console.log('Proximity reading:', proximitySensor.distance);
                        sensorData.proximity.distance = proximitySensor.distance;
                        if (isRecording) {
                            logSensorData('Proximity', sensorData.proximity);
                        }
                    });
                    proximitySensor.addEventListener('error', function(event) {
                        console.error('Proximity sensor error:', event.error);
                    });
                    proximitySensor.start();
                    proximitySensorInitialized = true;
                    console.log('ProximitySensor initialized successfully');
                } catch (error) {
                    console.warn('ProximitySensor not available:', error);
                }
            }
            
            // Method 2: Legacy deviceproximity event (BlackBerry Passport likely uses this)
            if (!proximitySensorInitialized && typeof window.addEventListener === 'function') {
                try {
                    console.log('Trying deviceproximity event...');
                    window.addEventListener('deviceproximity', function(event) {
                        console.log('Device proximity event:', event.value, 'min:', event.min, 'max:', event.max);
                        sensorData.proximity.distance = event.value;
                        if (isRecording) {
                            logSensorData('Proximity', sensorData.proximity);
                        }
                    });
                    proximitySensorInitialized = true;
                    console.log('Device proximity event listener set up');
                } catch (error) {
                    console.warn('Device proximity event not available:', error);
                }
            }
            
            // Method 3: BlackBerry WebWorks API (if available)
            if (!proximitySensorInitialized && typeof blackberry !== 'undefined' && blackberry.sensors) {
                try {
                    console.log('Trying BlackBerry WebWorks proximity sensor...');
                    if (blackberry.sensors.addEventListener) {
                        blackberry.sensors.addEventListener('deviceproximity', function(info) {
                            console.log('BlackBerry proximity sensor:', info);
                            sensorData.proximity.distance = info.distance || info.value || 0;
                            if (isRecording) {
                                logSensorData('Proximity', sensorData.proximity);
                            }
                        });
                        proximitySensorInitialized = true;
                        console.log('BlackBerry WebWorks proximity sensor initialized');
                    }
                } catch (error) {
                    console.warn('BlackBerry WebWorks proximity sensor not available:', error);
                }
            }
            
            // Method 4: User proximity event (simpler boolean proximity)
            if (!proximitySensorInitialized && typeof window.addEventListener === 'function') {
                try {
                    console.log('Trying userproximity event...');
                    window.addEventListener('userproximity', function(event) {
                        console.log('User proximity event:', event.near);
                        // Convert boolean to distance estimate
                        sensorData.proximity.distance = event.near ? 1 : 10;
                        if (isRecording) {
                            logSensorData('Proximity', { distance: sensorData.proximity.distance, near: event.near });
                        }
                    });
                    proximitySensorInitialized = true;
                    console.log('User proximity event listener set up');
                } catch (error) {
                    console.warn('User proximity event not available:', error);
                }
            }
            
            // Method 5: Alternative proximity sensor activation approaches
            if (!proximitySensorInitialized) {
                console.log('Trying alternative proximity sensor activation methods...');
                
                // Method 5a: Touch-based proximity simulation
                var touchProximityActive = false;
                try {
                    document.addEventListener('touchstart', function(event) {
                        console.log('Touch detected - simulating proximity near');
                        sensorData.proximity.distance = 0;
                        sensorData.proximity.near = true;
                        touchProximityActive = true;
                        
                        if (isRecording) {
                            logSensorData('Proximity', { 
                                distance: 0,
                                near: true,
                                method: 'touch_simulation'
                            });
                        }
                    });
                    
                    document.addEventListener('touchend', function(event) {
                        console.log('Touch ended - simulating proximity far');
                        setTimeout(function() {
                            sensorData.proximity.distance = Math.random() * 10 + 5;
                            sensorData.proximity.near = false;
                            
                            if (isRecording) {
                                logSensorData('Proximity', { 
                                    distance: sensorData.proximity.distance,
                                    near: false,
                                    method: 'touch_simulation'
                                });
                            }
                        }, 500); // Delay to simulate sensor response
                    });
                    
                    console.log('Touch-based proximity simulation enabled');
                } catch (e) {
                    console.log('Touch proximity simulation failed:', e);
                }
                
                // Method 5b: Orientation-based proximity simulation
                try {
                    var lastOrientation = { alpha: 0, beta: 0, gamma: 0 };
                    var orientationChangeCount = 0;
                    
                    window.addEventListener('deviceorientation', function(event) {
                        var orientationChange = Math.abs(event.alpha - lastOrientation.alpha) +
                                              Math.abs(event.beta - lastOrientation.beta) +
                                              Math.abs(event.gamma - lastOrientation.gamma);
                        
                        if (orientationChange > 15) {
                            orientationChangeCount++;
                            console.log('Significant orientation change detected:', orientationChange);
                            
                            // Simulate proximity based on device tilt (face down = near)
                            var isNear = Math.abs(event.beta) > 60; // Device tilted significantly
                            sensorData.proximity.distance = isNear ? Math.random() * 2 : Math.random() * 8 + 3;
                            sensorData.proximity.near = isNear;
                            
                            if (isRecording) {
                                logSensorData('Proximity', { 
                                    distance: sensorData.proximity.distance,
                                    near: sensorData.proximity.near,
                                    method: 'orientation_simulation',
                                    orientationChange: orientationChange,
                                    beta: event.beta
                                });
                            }
                            
                            console.log('Proximity simulated from orientation - distance:', 
                                       sensorData.proximity.distance.toFixed(1), 'near:', sensorData.proximity.near);
                        }
                        
                        lastOrientation = { alpha: event.alpha, beta: event.beta, gamma: event.gamma };
                    });
                    
                    console.log('Orientation-based proximity simulation enabled');
                } catch (e) {
                    console.log('Orientation proximity simulation failed:', e);
                }
                
                console.log('Alternative proximity sensor methods initialized');
            }
            
            // Battery API
            if ('getBattery' in navigator) {
                navigator.getBattery().then(function(battery) {
                    function updateBatteryInfo() {
                        sensorData.battery.level = Math.round(battery.level * 100);
                        sensorData.battery.charging = battery.charging;
                        if (isRecording) {
                            logSensorData('Battery', sensorData.battery);
                        }
                    }
                    
                    updateBatteryInfo();
                    battery.addEventListener('chargingchange', updateBatteryInfo);
                    battery.addEventListener('levelchange', updateBatteryInfo);
                    
                    console.log('Battery API initialized');
                });
            } else if ('battery' in navigator) {
                // Fallback for older API
                var battery = navigator.battery;
                sensorData.battery.level = Math.round(battery.level * 100);
                sensorData.battery.charging = battery.charging;
            }
            
            // Network Information API
            if ('connection' in navigator) {
                var connection = navigator.connection;
                sensorData.network.type = connection.effectiveType || connection.type || 'unknown';
                sensorData.network.speed = connection.downlink || 0;
                
                connection.addEventListener('change', function() {
                    sensorData.network.type = connection.effectiveType || connection.type || 'unknown';
                    sensorData.network.speed = connection.downlink || 0;
                    if (isRecording) {
                        logSensorData('Network', sensorData.network);
                    }
                });
                
                console.log('Network information API initialized');
            }
        }
        
        // Initialize device information
        function initializeDeviceInfo() {
            // User Agent (ES5 compatible)
            var userAgent = navigator.userAgent;
            document.getElementById('userAgent').textContent = 
                userAgent.indexOf('BlackBerry') !== -1 ? 'BlackBerry' : 'Other';
            
            // Screen information
            document.getElementById('screenInfo').textContent = 
                screen.width + 'x' + screen.height;
            
            // Memory information (with error handling)
            try {
                if (typeof performance !== 'undefined' && performance.memory) {
                    document.getElementById('memoryInfo').textContent = 
                        Math.round(performance.memory.usedJSHeapSize / 1024 / 1024) + 'MB';
                } else {
                    document.getElementById('memoryInfo').textContent = 'Unknown';
                }
            } catch (e) {
                document.getElementById('memoryInfo').textContent = 'Unknown';
            }
            
            // Connection information
            if ('connection' in navigator) {
                document.getElementById('connectionInfo').textContent = 
                    navigator.connection.effectiveType || 'Unknown';
            } else {
                document.getElementById('connectionInfo').textContent = 'Unknown';
            }
            
            // Platform information
            document.getElementById('platformInfo').textContent = navigator.platform;
            
            // Language information
            document.getElementById('languageInfo').textContent = navigator.language;
        }
        
        // Update display elements
        function updateDisplay() {
            // Update accelerometer display
            document.getElementById('accelX').textContent = sensorData.accelerometer.x.toFixed(2);
            document.getElementById('accelY').textContent = sensorData.accelerometer.y.toFixed(2);
            document.getElementById('accelZ').textContent = sensorData.accelerometer.z.toFixed(2);
            document.getElementById('accelMag').textContent = sensorData.accelerometer.magnitude.toFixed(2);
            
            // Update gyroscope display
            document.getElementById('gyroAlpha').textContent = sensorData.gyroscope.alpha.toFixed(2);
            document.getElementById('gyroBeta').textContent = sensorData.gyroscope.beta.toFixed(2);
            document.getElementById('gyroGamma').textContent = sensorData.gyroscope.gamma.toFixed(2);
            document.getElementById('gyroRate').textContent = sensorData.gyroscope.rate.toFixed(2);
            
            // Update magnetometer display
            document.getElementById('magnetHeading').textContent = Math.round(sensorData.magnetometer.heading) + '°';
            document.getElementById('magnetAccuracy').textContent = sensorData.magnetometer.accuracy > 0 ? 'High' : 'Low';
            document.getElementById('magnetDirection').textContent = getCompassDirection(sensorData.magnetometer.heading);
            
            // Update orientation display
            document.getElementById('orientMode').textContent = sensorData.orientation.mode;
            document.getElementById('orientAngle').textContent = sensorData.orientation.angle + '°';
            // ES5 compatible screen orientation check
            var orientLock = 'No';
            try {
                if (typeof screen !== 'undefined' && screen.orientation && screen.orientation.lock) {
                    orientLock = 'Yes';
                }
            } catch (e) {
                orientLock = 'Unknown';
            }
            document.getElementById('orientLock').textContent = orientLock;
            
            // Update environmental sensors
            document.getElementById('lightValue').textContent = 
                sensorData.light.level > 0 ? sensorData.light.level + ' lux' : '-- lux';
            document.getElementById('lightBar').style.width = 
                Math.min(sensorData.light.level / 1000 * 100, 100) + '%';
            
            // Update light sensor method status
            var lightStatus = document.getElementById('lightMethodStatus');
            if (sensorData.light.level === 500) {
                lightStatus.textContent = 'Test Mode';
                lightStatus.style.color = '#ff9900';
            } else if (sensorData.light.level > 0 && sensorData.light.level < 50) {
                lightStatus.textContent = 'Simulated (Dark)';
                lightStatus.style.color = '#4444aa';
            } else if (sensorData.light.level > 0) {
                lightStatus.textContent = 'Simulated (Bright)';
                lightStatus.style.color = '#aa6600';
            } else {
                lightStatus.textContent = 'Hardware present, API unsupported';
                lightStatus.style.color = '#cc6600';
            }
            
            document.getElementById('proximityValue').textContent = 
                sensorData.proximity.distance > 0 ? sensorData.proximity.distance.toFixed(1) + ' cm' : '-- cm';
            document.getElementById('proximityBar').style.width = 
                Math.min(sensorData.proximity.distance / 10 * 100, 100) + '%';
            
            // Update proximity sensor method status
            var proximityStatus = document.getElementById('proximityMethodStatus');
            if (sensorData.proximity.distance > 0) {
                proximityStatus.textContent = sensorData.proximity.near ? 'Near' : 'Far';
                proximityStatus.style.color = sensorData.proximity.near ? '#ff6600' : '#00aa00';
            } else {
                proximityStatus.textContent = 'Touch/Tilt to test';
                proximityStatus.style.color = '#666';
            }
            
            document.getElementById('batteryValue').textContent = sensorData.battery.level + '%';
            document.getElementById('batteryBar').style.width = sensorData.battery.level + '%';
            
            document.getElementById('networkValue').textContent = sensorData.network.type;
            document.getElementById('networkInfo').textContent = 
                sensorData.network.speed > 0 ? sensorData.network.speed + ' Mbps' : 'Speed unknown';
            
            // Update motion visualization
            updateMotionVisualization();
            
            // Update log count
            document.getElementById('logCount').textContent = dataLog.length + ' entries';
        }
        
        // Update motion visualization
        function updateMotionVisualization() {
            var dot = document.getElementById('motionDot');
            var maxOffset = 50; // Maximum pixels from center
            
            // Use accelerometer data for visualization
            var xOffset = (sensorData.accelerometer.x / 10) * maxOffset;
            var yOffset = (sensorData.accelerometer.y / 10) * maxOffset;
            
            // Limit to circle bounds
            var distance = Math.sqrt(xOffset * xOffset + yOffset * yOffset);
            if (distance > maxOffset) {
                xOffset = (xOffset / distance) * maxOffset;
                yOffset = (yOffset / distance) * maxOffset;
            }
            
            dot.style.transform = 'translate(' + 
                (xOffset - 4) + 'px, ' + 
                (yOffset - 4) + 'px)';
            
            // Change color based on motion intensity
            var intensity = sensorData.accelerometer.magnitude;
            if (intensity > 15) {
                dot.style.backgroundColor = '#f44336'; // Red - high motion
            } else if (intensity > 10) {
                dot.style.backgroundColor = '#ff9800'; // Orange - medium motion
            } else {
                dot.style.backgroundColor = '#4CAF50'; // Green - low motion
            }
        }
        
        // Get compass direction from heading
        function getCompassDirection(heading) {
            var directions = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'];
            var index = Math.round(heading / 45) % 8;
            return directions[index];
        }
        
        // Log sensor data
        function logSensorData(sensorType, data) {
            var now = new Date();
            // ES5 compatible time formatting
            var hours = now.getHours();
            var minutes = now.getMinutes();
            var seconds = now.getSeconds();
            var timeStr = (hours < 10 ? '0' : '') + hours + ':' + 
                         (minutes < 10 ? '0' : '') + minutes + ':' +
                         (seconds < 10 ? '0' : '') + seconds;
            
            var logEntry = {
                time: timeStr,
                timestamp: now.getTime(),
                sensor: sensorType,
                data: JSON.parse(JSON.stringify(data)) // Deep copy
            };
            
            dataLog.unshift(logEntry);
            
            // Keep only last N entries
            if (dataLog.length > maxLogEntries) {
                dataLog = dataLog.slice(0, maxLogEntries);
            }
            
            updateLogDisplay();
        }
        
        // Update log display
        function updateLogDisplay() {
            var container = document.getElementById('logEntries');
            var html = '';
            
            for (var i = 0; i < Math.min(dataLog.length, 10); i++) {
                var entry = dataLog[i];
                var dataStr = '';
                
                if (entry.sensor === 'Accelerometer') {
                    dataStr = 'X:' + entry.data.x.toFixed(1) + ' Y:' + entry.data.y.toFixed(1) + ' Z:' + entry.data.z.toFixed(1);
                } else if (entry.sensor === 'Gyroscope') {
                    dataStr = 'α:' + entry.data.alpha.toFixed(1) + ' β:' + entry.data.beta.toFixed(1) + ' γ:' + entry.data.gamma.toFixed(1);
                } else if (entry.sensor === 'Magnetometer') {
                    dataStr = 'Heading:' + Math.round(entry.data.heading) + '°';
                } else if (entry.sensor === 'Battery') {
                    dataStr = entry.data.level + '% ' + (entry.data.charging ? 'Charging' : 'Not charging');
                } else {
                    dataStr = JSON.stringify(entry.data);
                }
                
                html += '<div class="log-entry">' +
                       '<span class="log-time">' + entry.time + '</span> ' +
                       '<span class="log-sensor">' + entry.sensor + '</span> ' +
                       '<span class="log-value">' + dataStr + '</span>' +
                       '</div>';
            }
            
            if (html === '') {
                html = '<div class="log-entry">' +
                      '<span class="log-time">--:--:--</span> ' +
                      '<span class="log-sensor">System</span> ' +
                      '<span class="log-value">No data recorded yet</span>' +
                      '</div>';
            }
            
            container.innerHTML = html;
        }
        
        // Start recording
        function startRecording() {
            isRecording = true;
            document.getElementById('recordingStatus').classList.add('recording');
            document.getElementById('startBtn').disabled = true;
            document.getElementById('stopBtn').disabled = false;
            
            logSensorData('System', { message: 'Recording started' });
            console.log('Sensor recording started');
        }
        
        // Stop recording
        function stopRecording() {
            isRecording = false;
            document.getElementById('recordingStatus').classList.remove('recording');
            document.getElementById('startBtn').disabled = false;
            document.getElementById('stopBtn').disabled = true;
            
            logSensorData('System', { message: 'Recording stopped' });
            console.log('Sensor recording stopped');
        }
        
        // Clear log
        function clearLog() {
            if (confirm('Clear all sensor data? This cannot be undone.')) {
                dataLog = [];
                updateLogDisplay();
                console.log('Sensor log cleared');
            }
        }
        
        // Test functions for debugging sensors
        function testLightSensor() {
            console.log('=== Testing Light Sensor ===');
            
            // Try to manually trigger light sensor events
            if (typeof window.addEventListener === 'function') {
                console.log('Adding temporary devicelight listener...');
                var testListener = function(event) {
                    console.log('TEST: Light sensor event received!', event);
                    showSuccess('Light sensor test: ' + event.value + ' lux');
                    window.removeEventListener('devicelight', testListener);
                };
                window.addEventListener('devicelight', testListener);
                
                // Remove listener after 10 seconds if no event
                setTimeout(function() {
                    window.removeEventListener('devicelight', testListener);
                    console.log('Light sensor test timeout - try covering/uncovering the light sensor');
                }, 10000);
            }
            
            // Try to access sensor APIs directly
            console.log('Checking for direct sensor access...');
            
            // Method 1: Check navigator.sensor
            if (navigator.sensor) {
                console.log('navigator.sensor found:', navigator.sensor);
                if (navigator.sensor.light) {
                    try {
                        navigator.sensor.light.getCurrentReading(function(reading) {
                            console.log('Direct navigator sensor reading:', reading);
                            showSuccess('Direct light reading: ' + (reading.value || reading.illuminance || 'unknown'));
                        });
                    } catch (e) {
                        console.log('Direct navigator sensor failed:', e);
                    }
                }
            }
            
            // Method 2: Check window.sensor
            if (window.sensor) {
                console.log('window.sensor found:', window.sensor);
                if (window.sensor.light) {
                    try {
                        window.sensor.light.getCurrentReading(function(reading) {
                            console.log('Direct window sensor reading:', reading);
                            showSuccess('Window light reading: ' + (reading.value || reading.illuminance || 'unknown'));
                        });
                    } catch (e) {
                        console.log('Direct window sensor failed:', e);
                    }
                }
            }
            
            // Method 3: Try to trigger sensor manually
            console.log('Attempting to manually trigger light sensor...');
            try {
                // Create a fake light event to test if the listener works
                var fakeEvent = new Event('devicelight');
                fakeEvent.value = 500; // 500 lux test value
                window.dispatchEvent(fakeEvent);
                console.log('Dispatched fake light event');
            } catch (e) {
                console.log('Could not dispatch fake event:', e);
            }
            
            // Method 4: Check for any light-related properties
            console.log('Checking for light-related properties...');
            if (typeof navigator !== 'undefined') {
                var navProps = Object.getOwnPropertyNames(navigator);
                var lightProps = navProps.filter(function(prop) {
                    return prop.toLowerCase().indexOf('light') !== -1;
                });
                if (lightProps.length > 0) {
                    console.log('Found light-related navigator properties:', lightProps);
                    lightProps.forEach(function(prop) {
                        console.log('navigator.' + prop + ':', navigator[prop]);
                    });
                }
            }
            
            // Try BlackBerry WebWorks API
            if (typeof blackberry !== 'undefined' && blackberry.sensors) {
                console.log('Testing BlackBerry WebWorks light sensor...');
                try {
                    blackberry.sensors.addEventListener('devicelight', function(info) {
                        console.log('BlackBerry light sensor test:', info);
                        showSuccess('BlackBerry light: ' + (info.lightLevel || info.value || 'unknown'));
                    });
                } catch (e) {
                    console.log('BlackBerry light sensor test failed:', e);
                }
            }
            
            showSuccess('Light sensor test initiated - try covering/uncovering the light sensor and check console');
        }
        
        function testProximitySensor() {
            console.log('=== Testing Proximity Sensor ===');
            
            // Try deviceproximity event
            if (typeof window.addEventListener === 'function') {
                console.log('Adding temporary deviceproximity listener...');
                var testListener = function(event) {
                    console.log('TEST: Proximity sensor event received!', event);
                    showSuccess('Proximity test: ' + event.value + ' cm');
                    window.removeEventListener('deviceproximity', testListener);
                };
                window.addEventListener('deviceproximity', testListener);
                
                setTimeout(function() {
                    window.removeEventListener('deviceproximity', testListener);
                    console.log('Proximity sensor test timeout');
                }, 5000);
            }
            
            // Try userproximity event
            if (typeof window.addEventListener === 'function') {
                console.log('Adding temporary userproximity listener...');
                var userTestListener = function(event) {
                    console.log('TEST: User proximity event received!', event);
                    showSuccess('User proximity test: ' + (event.near ? 'Near' : 'Far'));
                    window.removeEventListener('userproximity', userTestListener);
                };
                window.addEventListener('userproximity', userTestListener);
                
                setTimeout(function() {
                    window.removeEventListener('userproximity', userTestListener);
                    console.log('User proximity sensor test timeout');
                }, 5000);
            }
            
            showSuccess('Proximity sensor test initiated - check console');
        }
        
        function requestPermissions() {
            console.log('=== Requesting Sensor Permissions ===');
            
            // Try to request permissions for various sensors
            if (navigator.permissions && navigator.permissions.query) {
                var permissions = ['ambient-light-sensor', 'accelerometer', 'gyroscope', 'magnetometer'];
                
                permissions.forEach(function(permission) {
                    navigator.permissions.query({name: permission}).then(function(result) {
                        console.log(permission + ' permission:', result.state);
                        if (result.state === 'prompt') {
                            console.log('Permission can be requested for:', permission);
                        }
                    }).catch(function(error) {
                        console.log('Permission query failed for ' + permission + ':', error);
                    });
                });
            } else {
                console.log('Permissions API not available');
            }
            
            // Try DeviceMotionEvent permission (iOS 13+)
            if (typeof DeviceMotionEvent !== 'undefined' && DeviceMotionEvent.requestPermission) {
                DeviceMotionEvent.requestPermission().then(function(response) {
                    console.log('DeviceMotion permission:', response);
                    showSuccess('Motion permission: ' + response);
                }).catch(function(error) {
                    console.log('DeviceMotion permission failed:', error);
                });
            }
            
            // Try DeviceOrientationEvent permission (iOS 13+)
            if (typeof DeviceOrientationEvent !== 'undefined' && DeviceOrientationEvent.requestPermission) {
                DeviceOrientationEvent.requestPermission().then(function(response) {
                    console.log('DeviceOrientation permission:', response);
                    showSuccess('Orientation permission: ' + response);
                }).catch(function(error) {
                    console.log('DeviceOrientation permission failed:', error);
                });
            }
            
            showSuccess('Permission requests sent - check console');
        }
        
        function debugSensors() {
            console.log('=== Current Sensor Status ===');
            console.log('Light level:', sensorData.light.level);
            console.log('Proximity distance:', sensorData.proximity.distance);
            console.log('Accelerometer:', sensorData.accelerometer);
            console.log('Gyroscope:', sensorData.gyroscope);
            console.log('Magnetometer:', sensorData.magnetometer);
            console.log('Battery:', sensorData.battery);
            console.log('Network:', sensorData.network);
            console.log('============================');
            
            // Show debug info in UI
            var debugInfo = 'Light: ' + sensorData.light.level + ' lux\\n' +
                           'Proximity: ' + sensorData.proximity.distance + ' cm\\n' +
                           'Accel: ' + sensorData.accelerometer.magnitude.toFixed(2) + ' m/s²\\n' +
                           'Gyro: ' + sensorData.gyroscope.rate.toFixed(2) + ' rad/s\\n' +
                           'Compass: ' + Math.round(sensorData.magnetometer.heading) + '°\\n' +
                           'Battery: ' + sensorData.battery.level + '%';
            
            alert('Current Sensor Readings:\\n\\n' + debugInfo);
        }
        
        // Export data
        function exportData() {
            if (dataLog.length === 0) {
                showError('No data to export');
                return;
            }
            
            var csvContent = 'Time,Timestamp,Sensor,Data\\n';
            for (var i = 0; i < dataLog.length; i++) {
                var entry = dataLog[i];
                csvContent += entry.time + ',' + entry.timestamp + ',' + 
                             entry.sensor + ',"' + JSON.stringify(entry.data) + '"\\n';
            }
            
            // Create download link (with fallback for older browsers)
            try {
                if (typeof Blob !== 'undefined' && window.URL && window.URL.createObjectURL) {
                    var blob = new Blob([csvContent], { type: 'text/csv' });
                    var url = window.URL.createObjectURL(blob);
                    var a = document.createElement('a');
                    a.href = url;
                    // ES5 compatible date formatting
                    var now = new Date();
                    var dateStr = now.getFullYear() + '-' + 
                                 (now.getMonth() + 1 < 10 ? '0' : '') + (now.getMonth() + 1) + '-' +
                                 (now.getDate() < 10 ? '0' : '') + now.getDate() + '_' +
                                 (now.getHours() < 10 ? '0' : '') + now.getHours() + '-' +
                                 (now.getMinutes() < 10 ? '0' : '') + now.getMinutes();
                    a.download = 'sensor_data_' + dateStr + '.csv';
                    document.body.appendChild(a);
                    a.click();
                    document.body.removeChild(a);
                    window.URL.revokeObjectURL(url);
                } else {
                    // Fallback: show data in alert for copy/paste
                    alert('Export not supported. Copy this data:\\n\\n' + csvContent.substring(0, 500) + '...');
                }
            } catch (e) {
                console.error('Export error:', e);
                showError('Export failed: ' + e.message);
            }
            
            showSuccess('Data exported successfully');
        }
        
        // Utility functions
        function showError(message) {
            var errorDiv = document.createElement('div');
            errorDiv.className = 'error-message';
            errorDiv.textContent = message;
            document.querySelector('.content').insertBefore(errorDiv, document.querySelector('.motion-viz'));
            
            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('.motion-viz'));
            
            setTimeout(function() {
                if (successDiv.parentNode) {
                    successDiv.parentNode.removeChild(successDiv);
                }
            }, 3000);
        }
        
        // Initialize when page loads
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', initApp);
        } else {
            initApp();
        }
        
        // Handle page unload
        window.addEventListener('beforeunload', function() {
            if (isRecording) {
                // Save data before leaving
                console.log('Page unloading, stopping recording');
            }
        });
        
        // Handle page visibility changes
        document.addEventListener('visibilitychange', function() {
            if (document.hidden) {
                console.log('Page hidden, sensors continue running');
            } else {
                console.log('Page visible, updating display');
            }
        });
    </script>
</body>
</html>'''

class SensorDashboardHandler(http.server.BaseHTTPRequestHandler):
    """Sensor Dashboard 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/sensor-data':
                self.handle_sensor_data_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-sensor-data':
                self.handle_save_sensor_data_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_sensor_data_api(self):
        """Handle sensor data API request"""
        try:
            conn = sqlite3.connect(DB_PATH)
            cursor = conn.cursor()
            
            cursor.execute('''
                SELECT timestamp, sensor_type, x_value, y_value, z_value, magnitude, additional_data
                FROM sensor_readings 
                ORDER BY timestamp DESC 
                LIMIT 50
            ''')
            
            results = cursor.fetchall()
            conn.close()
            
            readings = []
            for result in results:
                readings.append({
                    'timestamp': result[0],
                    'sensor_type': result[1],
                    'x_value': result[2],
                    'y_value': result[3],
                    'z_value': result[4],
                    'magnitude': result[5],
                    'additional_data': result[6]
                })
            
            self.send_json({'readings': readings})
        except Exception as e:
            print(f"Error handling sensor data API: {e}")
            self.send_json({'error': 'Failed to load sensor data'}, 500)
    
    def handle_save_sensor_data_api(self):
        """Handle save sensor data 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()
            
            # Save sensor readings
            for reading in data.get('readings', []):
                cursor.execute('''
                    INSERT INTO sensor_readings 
                    (timestamp, sensor_type, x_value, y_value, z_value, magnitude, additional_data)
                    VALUES (?, ?, ?, ?, ?, ?, ?)
                ''', (
                    reading.get('timestamp'),
                    reading.get('sensor_type'),
                    reading.get('x_value', 0),
                    reading.get('y_value', 0),
                    reading.get('z_value', 0),
                    reading.get('magnitude', 0),
                    reading.get('additional_data', '')
                ))
            
            conn.commit()
            conn.close()
            
            self.send_json({'status': 'success', 'message': 'Sensor data saved'})
        except Exception as e:
            print(f"Error saving sensor data: {e}")
            self.send_json({'status': 'error', 'message': 'Failed to save sensor data'}, 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 Sensor Dashboard server"""
    try:
        # Initialize database
        init_database()
        
        print("=" * 60)
        print("BlackBerry Passport Multi-Sensor Dashboard")
        print("=" * 60)
        print(f"Port: {port}")
        print(f"Database: {DB_PATH}")
        print(f"Base Directory: {BASE_DIR}")
        print("")
        print("Available Sensors:")
        print("- Accelerometer (motion detection)")
        print("- Gyroscope (rotation rates)")
        print("- Magnetometer (compass heading)")
        print("- Device Orientation (screen rotation)")
        print("- Ambient Light Sensor")
        print("- Proximity Sensor")
        print("- Battery Status")
        print("- Network Information")
        print("- Device Information")
        print("")
        print("Features:")
        print("- Real-time sensor monitoring")
        print("- Motion visualization")
        print("- Data logging and export")
        print("- ES5 compatible JavaScript")
        print("- BlackBerry Passport optimized UI")
        print("")
        print(f"🚀 Starting server on http://localhost:{port}")
        print("📱 Optimized for BlackBerry Passport")
        print("📊 Monitor all your device sensors!")
        print("⏹️  Press Ctrl+C to stop")
        print("=" * 60)
        
        with ThreadedTCPServer(("", port), SensorDashboardHandler) as httpd:
            httpd.serve_forever()
            
    except KeyboardInterrupt:
        print("\n" + "=" * 60)
        print("👋 Shutting down Sensor Dashboard")
        print("=" * 60)
    except Exception as e:
        print(f"❌ Server error: {e}")
        sys.exit(1)

if __name__ == "__main__":
    run_server()
