2025-10-22 08:43:20 +02:00

354 lines
10 KiB
Dart

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/foundation.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
/// Einfacher PTV API Service mit statischen Methoden
class PtvApiServiceSimple {
/// Private Konstruktor
PtvApiServiceSimple._();
/// Base URL der PTV API
static const String _baseUrl = 'https://api.myptv.com/geocoding/v1/locations/by-position';
/// Standard Sprache
static const String _defaultLanguage = 'de';
/// Timeout in Sekunden
static const int _timeoutSeconds = 15;
/// API Key aus .env Datei
static String get _apiKey => dotenv.env['PTVE_API_KEY'] ?? '';
/// HTTP Headers
static Map<String, String> get _headers => {
'Accept': 'application/json',
'Content-Type': 'application/json',
'ApiKey': _apiKey,
};
/// Hauptmethode: Holt Location-Daten für gegebene Koordinaten
///
/// Beispiel URL: https://api.myptv.com/geocoding/v1/locations/by-position/48.208282/14.214758?language=de
///
/// [latitude] - Breitengrad (z.B. 48.208282)
/// [longitude] - Längengrad (z.B. 14.214758)
/// [language] - Sprache für Antwort (default: 'de')
///
/// Returns Map mit API-Response oder null bei Fehler
static Future<Map<String, dynamic>?> getLocationsByPosition({
required double latitude,
required double longitude,
String language = _defaultLanguage,
}) async {
try {
// Validiere Koordinaten
if (!_isValidCoordinate(latitude, longitude)) {
if (kDebugMode) {
print('❌ Ungültige Koordinaten: lat=$latitude, lng=$longitude');
}
return null;
}
// Lade .env falls API Key leer
if (_apiKey.isEmpty) {
await dotenv.load(fileName: ".env");
if (_apiKey.isEmpty) {
if (kDebugMode) {
print('❌ PTVE_API_KEY nicht in .env gefunden');
}
return null;
}
}
// Baue URL
final url = '$_baseUrl/$latitude/$longitude?language=$language';
if (kDebugMode) {
print('🌐 PTV API Request: $url');
print('🔑 API Key vorhanden: ${_apiKey.isNotEmpty}');
}
// HTTP GET Request
final response = await http
.get(
Uri.parse(url),
headers: _headers,
)
.timeout(Duration(seconds: _timeoutSeconds));
if (kDebugMode) {
print('📡 Response Status: ${response.statusCode}');
}
// Verarbeite Response
if (response.statusCode == 200) {
final jsonData = json.decode(response.body) as Map<String, dynamic>;
if (kDebugMode) {
print('✅ API Request erfolgreich');
print('📍 Locations gefunden: ${(jsonData['locations'] as List?)?.length ?? 0}');
}
return jsonData;
} else {
if (kDebugMode) {
print('❌ API Fehler: ${response.statusCode}');
print('📄 Response Body: ${response.body}');
}
return null;
}
} catch (e) {
if (kDebugMode) {
print('❌ Exception beim API Aufruf: $e');
}
return null;
}
}
/// Erweiterte Methode mit zusätzlichen Parametern
static Future<Map<String, dynamic>?> getLocationsByPositionAdvanced({
required double latitude,
required double longitude,
String language = _defaultLanguage,
int? maxResults,
int? radius,
}) async {
try {
// Baue URL mit zusätzlichen Query-Parametern
String url = '$_baseUrl/$latitude/$longitude?language=$language';
if (maxResults != null && maxResults > 0) {
url += '&maxResults=$maxResults';
}
if (radius != null && radius > 0) {
url += '&radius=$radius';
}
if (kDebugMode) {
print('🌐 PTV API Advanced Request: $url');
}
final response = await http
.get(
Uri.parse(url),
headers: _headers,
)
.timeout(Duration(seconds: _timeoutSeconds));
if (response.statusCode == 200) {
return json.decode(response.body) as Map<String, dynamic>;
} else {
if (kDebugMode) {
print('❌ Advanced API Fehler: ${response.statusCode}');
}
return null;
}
} catch (e) {
if (kDebugMode) {
print('❌ Exception bei erweiterter API Abfrage: $e');
}
return null;
}
}
/// Hilfsmethoden
/// Validiert GPS-Koordinaten
static bool _isValidCoordinate(double latitude, double longitude) {
return latitude >= -90 &&
latitude <= 90 &&
longitude >= -180 &&
longitude <= 180;
}
/// Prüft API-Verfügbarkeit mit Test-Request
static Future<bool> testApiConnection() async {
try {
if (kDebugMode) {
print('\n🧪 PTV API CONNECTION TEST 🧪');
}
// Test mit Wien Koordinaten
final result = await getLocationsByPosition(
latitude: 48.2082,
longitude: 16.3738,
);
final success = result != null;
if (kDebugMode) {
print(success ? '✅ API Test erfolgreich' : '❌ API Test fehlgeschlagen');
print('🧪 TEST ABGESCHLOSSEN\n');
}
return success;
} catch (e) {
if (kDebugMode) {
print('❌ Test Exception: $e');
print('🧪 TEST ABGESCHLOSSEN\n');
}
return false;
}
}
/// Debugging: Zeigt Service-Informationen
static void printServiceInfo() {
if (kDebugMode) {
print('\n📋 PTV API SERVICE INFO 📋');
print('Base URL: $_baseUrl');
print('Default Language: $_defaultLanguage');
print('Timeout: ${_timeoutSeconds}s');
print('API Key verfügbar: ${_apiKey.isNotEmpty}');
print('API Key Length: ${_apiKey.length}');
print('📋 SERVICE INFO END 📋\n');
}
}
/// Demonstration der API-Verwendung
static Future<void> runDemo() async {
if (kDebugMode) {
print('\n🚀 PTV API DEMO START 🚀');
// Service Info
printServiceInfo();
// Test Connection
await testApiConnection();
// Beispiel 1: Traun, Österreich
print('📍 Beispiel 1: Traun, Österreich');
final traunResult = await getLocationsByPosition(
latitude: 48.208282,
longitude: 14.214758,
);
if (traunResult != null) {
final locations = traunResult['locations'] as List?;
if (locations != null && locations.isNotEmpty) {
final firstLocation = locations.first;
print('✅ Gefunden: ${firstLocation['formattedAddress']}');
print('📍 Koordinaten: ${firstLocation['referencePosition']['latitude']}, ${firstLocation['referencePosition']['longitude']}');
final quality = firstLocation['quality'];
if (quality != null) {
print('🎯 Genauigkeit: ${quality['distance']}m');
}
}
} else {
print('❌ Keine Daten für Traun erhalten');
}
// Beispiel 2: Wien mit erweiterten Parametern
print('\n📍 Beispiel 2: Wien (erweitert)');
final wienResult = await getLocationsByPositionAdvanced(
latitude: 48.2082,
longitude: 16.3738,
maxResults: 3,
radius: 500,
);
if (wienResult != null) {
final locations = wienResult['locations'] as List?;
print('✅ Wien Locations gefunden: ${locations?.length ?? 0}');
if (locations != null) {
for (int i = 0; i < locations.length && i < 3; i++) {
final location = locations[i];
print(' ${i + 1}. ${location['formattedAddress']}');
}
}
}
print('🚀 DEMO ABGESCHLOSSEN 🚀\n');
}
}
}
/// Utility-Klasse für häufige PTV-Operationen
class PtvApiUtils {
/// Extrahiert die beste Location aus der API-Response
static Map<String, dynamic>? getBestLocation(Map<String, dynamic> apiResponse) {
final locations = apiResponse['locations'] as List?;
if (locations == null || locations.isEmpty) return null;
// Suche Location mit geringster Distanz
Map<String, dynamic>? bestLocation;
double? bestDistance;
for (final location in locations) {
final quality = location['quality'];
if (quality != null) {
final distance = (quality['distance'] as num?)?.toDouble();
if (distance != null && (bestDistance == null || distance < bestDistance)) {
bestDistance = distance;
bestLocation = location;
}
}
}
return bestLocation ?? locations.first;
}
/// Extrahiert formatierte Adresse
static String? getFormattedAddress(Map<String, dynamic> apiResponse) {
final bestLocation = getBestLocation(apiResponse);
return bestLocation?['formattedAddress'] as String?;
}
/// Extrahiert Koordinaten
static Map<String, double>? getCoordinates(Map<String, dynamic> apiResponse) {
final bestLocation = getBestLocation(apiResponse);
final refPos = bestLocation?['referencePosition'];
if (refPos != null) {
return {
'latitude': (refPos['latitude'] as num?)?.toDouble() ?? 0.0,
'longitude': (refPos['longitude'] as num?)?.toDouble() ?? 0.0,
};
}
return null;
}
/// Prüft Qualität der Location
static String getQualityLevel(Map<String, dynamic> apiResponse) {
final bestLocation = getBestLocation(apiResponse);
final quality = bestLocation?['quality'];
if (quality != null) {
final distance = (quality['distance'] as num?)?.toDouble() ?? 999999;
if (distance <= 10) return 'Sehr hoch';
if (distance <= 50) return 'Hoch';
if (distance <= 100) return 'Mittel';
if (distance <= 500) return 'Niedrig';
return 'Sehr niedrig';
}
return 'Unbekannt';
}
/// Konvertiert API-Response zu lesbarem String
static String formatLocationInfo(Map<String, dynamic> apiResponse) {
final bestLocation = getBestLocation(apiResponse);
if (bestLocation == null) return 'Keine Location gefunden';
final address = bestLocation['formattedAddress'] ?? 'Unbekannte Adresse';
final refPos = bestLocation['referencePosition'];
final quality = bestLocation['quality'];
String info = 'Adresse: $address\n';
if (refPos != null) {
info += 'Koordinaten: ${refPos['latitude']}, ${refPos['longitude']}\n';
}
if (quality != null) {
info += 'Genauigkeit: ${quality['distance']}m (${getQualityLevel(apiResponse)})\n';
}
return info;
}
}