| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824 |
- import 'dart:developer';
- import 'dart:io';
- //import 'package:dio/adapter.dart';
- import 'package:dio/dio.dart';
- import 'package:dio/io.dart';
- import 'package:dio_cookie_manager/dio_cookie_manager.dart';
- import 'package:cookie_jar/cookie_jar.dart';
- import 'package:flutter_riverpod/flutter_riverpod.dart';
- import 'package:hive_flutter/hive_flutter.dart';
- // import 'package:flutter_riverpod/flutter_riverpod.dart';
- import '../api/dio_exceptions.dart';
- import 'package:html/dom.dart' as dom;
- import 'package:intl/intl.dart';
- import 'package:html/parser.dart';
- // import 'package:path_provider/path_provider.dart';
- import 'package:syncfusion_flutter_pdf/pdf.dart';
- // import 'dio_logger.dart';
- final crewlinkapiProvider = Provider<CrewlinkApi>((ref) {
- return CrewlinkApi();
- });
- class CrewlinkApi {
- static int maxDaysRoster = 59;
- static int maxDaysCrewlist = 30;
- // static final CrewlinkApi instance = CrewlinkApi._();
- late Dio _dio;
- String realUrl = "https://crewlink.flytunisair.net/crewlink";
- String get baseUrl => realUrl;
- Map<String, dynamic> get _headers => {
- "Host": Uri.parse(realUrl).host,
- "User-Agent":
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:103.0) Gecko/20100101 Firefox/103.0",
- "Accept":
- "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
- "Accept-Language": "en-US,en;q=0.5",
- "Accept-Encoding": "gzip, deflate, br",
- "Origin": Uri.parse(realUrl).host,
- "Connection": "keep-alive",
- };
- // CrewlinkApi._() {
- CrewlinkApi() {
- {
- _dio = Dio();
- //ignore bad certificate
- _dio.httpClientAdapter = IOHttpClientAdapter(
- createHttpClient: () {
- // Don't trust any certificate just because their root cert is trusted.
- final HttpClient client =
- HttpClient(context: SecurityContext(withTrustedRoots: false));
- // You can test the intermediate / root cert here. We just ignore it.
- client.badCertificateCallback = (cert, host, port) => true;
- return client;
- },
- );
- //default param
- _dio = _dio
- ..options.baseUrl = baseUrl
- ..options.followRedirects = false
- ..options.connectTimeout = const Duration(seconds: 5000)
- ..options.receiveTimeout = const Duration(seconds: 10000)
- ..options.responseType = ResponseType.plain
- ..options.validateStatus = (status) {
- return (status ?? 999) < 500;
- };
- //addcookie manager
- _dio.interceptors.add(CookieManager(CookieJar()));
- //add logger
- // _dio.interceptors.add(DioLogger(
- // baseurl: false,
- // path: true,
- // statuscode: true,
- // reqdata: true,
- // resdata: true));
- //error interceptor
- //add header interceptor
- _dio.interceptors.add(InterceptorsWrapper(onRequest: (options, handler) {
- options.headers.addAll(_headers);
- if (options.method == "POST") {
- options.headers
- .addAll({"Content-Type": "application/x-www-form-urlencoded"});
- }
- return handler.next(options); //continue
- }, onResponse: (response, handler) {
- return handler.next(response); // continue
- }, onError: (DioException e, handler) {
- // Do something with response error
- log("crewlinkapi: onerror: ${e.type} ${e.message}");
- return handler.resolve(Response(
- statusCode: e.response?.statusCode,
- statusMessage: DioExceptions.fromDioException(e).message,
- data: e.response?.data ?? "",
- headers: e.response?.headers,
- requestOptions: e.requestOptions));
- }));
- }
- }
- Future login({String? username, String? password}) async {
- storedusername = username ?? storedusername;
- storedpassword = password ?? storedpassword;
- var res = await _dio.get(
- "/crewlink.jsp?crewlinkOperation=crewlinkForCrew&resetSession=Y",
- );
- res = await _dio.post(
- '/clApp',
- data: {
- "crewlinkService": "crewlinkForCrew",
- "crewlinkOperation": "loadMainFrameSet",
- "crewlinkSourcePage": "spStartup",
- "crewlinkUserName": storedusername,
- "crewlinkPassword": storedpassword
- },
- );
- String? error;
- if (res.statusCode == 302) {
- error = "invalid username or password";
- } else if (res.statusCode == 200) {
- error = null;
- } else {
- error = res.statusMessage;
- }
- return {
- 'error': error,
- 'data': {"logged": (res.statusCode == 200)},
- 'meta': {
- "user": username,
- "pass": password,
- "logged": (res.statusCode == 200),
- "statuscode": res.statusCode
- }
- };
- }
- Future rosterMinMax({bool loginfirst = false}) async {
- if (loginfirst) {
- var x = await login();
- if ((x["data"]["logged"] ?? false) == false) return x;
- }
- var res = await _dio.get(
- "/clApp?crewlinkService=individualDutyPlan&crewlinkOperation=default&crewlinkSourcePage=spCrew",
- );
- var mindate = (RegExp(
- r"(?<=minDateMinus1 = getDateFromFormat\(').+?(?=', 'yyyy-MM-dd'\);)",
- dotAll: true)
- .stringMatch(res.data ?? ""));
- var maxdate = (RegExp(
- r"(?<=maxDatePlus1 = getDateFromFormat\(').+?(?=', 'yyyy-MM-dd'\);)",
- dotAll: true)
- .stringMatch(res.data ?? ""));
- rostermin = mindate ?? "";
- rostermax = maxdate ?? "";
- String? error;
- if (res.statusCode == 302) {
- if (!loginfirst) return await rosterMinMax(loginfirst: true);
- } else if (res.statusCode == 200) {
- error = null;
- } else {
- error = res.statusMessage;
- }
- return {
- 'error': error,
- 'data': {"mindate": mindate, "maxdate": maxdate},
- 'meta': {
- "user": storedusername,
- "pass": storedpassword,
- "statuscode": res.statusCode
- }
- };
- }
- Future roster(
- {required String start,
- required String end,
- required String fileid,
- CancelToken? cancelToken,
- ProgressCallback? progressCallback,
- bool loginfirst = false}) async {
- if (loginfirst) {
- var x = await login();
- if ((x["data"]["logged"] ?? false) == false) return x;
- }
- var res = await _dio.post("/clApp", data: {
- "crewlinkService": "individualDutyPlan",
- "crewlinkOperation": "makeReport",
- "buddyName": "",
- "beginDate": start,
- "endDate": end
- });
- String? pdflink =
- (RegExp(r'(?<=file=\/crewlink)(.+\.pdf?)(?=")', dotAll: true)
- .stringMatch(res.data ?? ""));
- String? msg = parse(res.data).querySelector(".errMsg")?.text.trim();
- //String fileid ="${(await getApplicationDocumentsDirectory()).path}/${DateFormat("yyyyMMddHHmm").format(DateTime.now())}_${storedusername}_${start}_$end.pdf";
- // String fileid =
- // "${(await getApplicationDocumentsDirectory()).path}/ROSTER_${storedusername}_${start}_$end.pdf";
- String? error;
- if (res.statusCode == 302) {
- if (!loginfirst) {
- return await roster(
- start: start,
- end: end,
- loginfirst: true,
- fileid: fileid,
- cancelToken: cancelToken,
- progressCallback: progressCallback);
- } else {
- return "invalid username or password";
- }
- } else if (res.statusCode == 200 && pdflink != null) {
- error = null;
- await _dio.download(pdflink, fileid,
- cancelToken: cancelToken, onReceiveProgress: progressCallback);
- } else if (res.statusMessage != "") {
- error = res.statusMessage;
- } else {
- error = null;
- }
- return {
- 'error': error,
- 'data': {
- "pdflink": pdflink,
- "msg": msg,
- ...pdflink != null ? {"id": fileid} : {},
- ...pdflink != null ? {"decoded": _decodeRoster(fileid)} : {}
- },
- 'meta': {
- "user": storedusername,
- "pass": storedpassword,
- "statuscode": res.statusCode
- }
- };
- }
- Future showCrewMinMax({bool loginfirst = false}) async {
- if (loginfirst) {
- var x = await login();
- if ((x["data"]["logged"] ?? false) == false) return x;
- }
- var res = await _dio.get(
- "/clApp?crewlinkService=showCrew&crewlinkOperation=default&crewlinkSourcePage=spCrew");
- var mindate = (RegExp(
- r"(?<=minDateMinus1 = getDateFromFormat\(').+?(?=', 'yyyy-MM-dd'\);)",
- dotAll: true)
- .stringMatch(res.data));
- var maxdate = (RegExp(
- r"(?<=maxDatePlus1 = getDateFromFormat\(').+?(?=', 'yyyy-MM-dd'\);)",
- dotAll: true)
- .stringMatch(res.data));
- showcrewmin = mindate ?? "";
- showcrewmax = maxdate ?? "";
- String? error;
- if (res.statusCode == 302) {
- if (!loginfirst) return await showCrewMinMax(loginfirst: true);
- } else if (res.statusCode == 200) {
- error = null;
- } else {
- error = res.statusMessage;
- }
- return {
- 'error': error,
- 'data': {"mindate": mindate, "maxdate": maxdate},
- 'meta': {
- "user": storedusername,
- "pass": storedpassword,
- "statuscode": res.statusCode
- }
- };
- }
- Future showCrew(
- {required String start,
- required String end,
- bool crewlist = false,
- String al = "",
- String fnum = "",
- String dep = "",
- String des = "",
- bool loginfirst = false}) async {
- //String cachekey = "|$start,$end,$al,$fnum,$dep,$des,$crewlist";
- //start format ddMMMyy
- if (loginfirst) {
- var x = await login();
- if ((x["data"]["logged"] ?? false) == false) return x;
- }
- var res = await showCrewMinMax();
- if (res["error"] != null) return res;
- res = await _dio.post('/clApp', data: {
- "buddyName": "",
- "depDatePeriodBegin": start,
- "depDatePeriodEnd": end,
- "fnAirline": al,
- "fnNumber": fnum,
- "depAp": dep,
- "arrAp": des,
- "crewlinkService": "showCrew",
- "crewlinkOperation": "showCrew",
- "crewlinkSourcePage": "spCrew"
- });
- var msg = parse(res.data).querySelector(".errMsg")?.text;
- List leglist = [];
- if (res.statusCode == 200 && (msg ?? "") == "") {
- res = await _dio
- .get("/clApp?crewlinkService=showCrew&crewlinkOperation=legList");
- leglist = parse(res.data)
- .querySelectorAll("table tbody tr")
- .map((dom.Element tr) => (tr.children
- .map((td) => ((parse(td.innerHtml)
- .querySelector('[name="indexOfLeg"]')
- ?.attributes["value"]
- .toString()
- .trim()) ??
- td.text.trim()))
- .toList()))
- .toList();
- // treat cabin: cockpit: DH Flight:
- leglist = leglist.map((x) {
- x[7] =
- "${(RegExp(r"Cockpit: (.*?)(DH Flight: |Cabin: |$)").firstMatch(x[7])?.group(1) ?? "").trim()}|${(RegExp(r"Cabin: (.*?)(DH Flight: |$)").firstMatch(x[7])?.group(1) ?? "").trim()}|${(RegExp(r"DH Flight: (.*?)$").firstMatch(x[7])?.group(1) ?? "").trim()}";
- return x;
- }).toList();
- if (crewlist) {
- var out = [];
- for (var leg in leglist) {
- await _dio.post("/clApp", data: {
- "crewlinkService": "showCrew",
- "crewlinkOperation": "clearCrewList",
- "crewlinkSourcePage": ""
- });
- var res = await _dio.post("/clApp", data: {
- "crewlinkService": "showCrew",
- "crewlinkOperation": "exploreFlight",
- "crewlinkSourcePage": "",
- "indexOfLeg": leg[0].toString()
- });
- // log("flt: ${res.data}");
- var flt =
- ((parse(res.data).querySelector("table tr th[colspan]")?.text) ??
- "\n\n\n\n\n\n\n")
- .split("\n")
- .skip(1)
- .map((e) => e.trim())
- .toList();
- // ..removeAt(6);
- var crew = [];
- if ((parse(res.data).querySelector(".errMsg")?.text != null)) {
- crew = [];
- } else {
- crew = (parse(res.data)
- .querySelectorAll("table tr")
- .map((e) =>
- e.text.split("\n").map((e) => e.trim()).skip(1).toList()
- ..removeAt(6))
- .skip(2))
- .toList();
- }
- // log("crew: $crew");
- out.add([
- leg[0],
- flt[0],
- flt[1],
- flt[2],
- flt[3],
- flt[4],
- flt[5],
- leg[7],
- crew
- ]);
- //log((flt).toString());
- }
- leglist = out;
- }
- }
- String? error;
- if (res.statusCode == 302) {
- if (!loginfirst) {
- return await showCrew(
- start: start,
- end: end,
- crewlist: crewlist,
- al: al,
- fnum: fnum,
- dep: dep,
- des: dep,
- loginfirst: true);
- }
- } else if (res.statusCode == 200) {
- error = null;
- } else {
- error = res.statusMessage;
- }
- return {
- 'error': error,
- 'data': {
- "leglist": leglist,
- "msg": msg,
- },
- 'meta': {
- "user": storedusername,
- "pass": storedpassword,
- "statuscode": res.statusCode
- }
- };
- }
- Future userInfo({bool loginfirst = false}) async {
- if (loginfirst) {
- var x = await login();
- if ((x["data"]["logged"] ?? false) == false) return x;
- }
- var res = await _dio.get("/HeaderPage.jsp");
- var data = (RegExp(
- r'(?<=\<td class="userInfo">)\s*<b>(.*?)<\/b>\s*(.+?)<br\/>\s*(.*?)\s(.{3})\s(.{3}).*?(?=\<\/td\>)',
- dotAll: true)
- .firstMatch(res.data));
- bool novalidsession = (res.data).indexOf("unknown user") > -1;
- String? error;
- if (novalidsession) {
- if (!loginfirst) return await userInfo(loginfirst: true);
- } else if (res.statusCode == 200) {
- error = null;
- } else {
- error = res.statusMessage;
- }
- return {
- 'error': error,
- 'data': {
- "tlc": data?.group(1),
- "name": data?.group(2),
- "qualif": (data?.group(3) ?? "").split(","),
- "base": data?.group(4),
- "sit": data?.group(5),
- },
- 'meta': {"user": storedusername, "pass": storedpassword}
- };
- }
- Future changePass({required String newpass, bool loginfirst = false}) async {
- if (loginfirst) {
- var x = await login();
- if ((x["data"]["logged"] ?? false) == false) return x;
- }
- var res = await _dio.get(
- "/clApp?crewlinkService=changePassword&crewlinkOperation=default&crewlinkSourcePage=spCrew");
- res = await _dio.post("/clApp", data: {
- "oldPassword": storedpassword,
- "newPassword1": newpass,
- "newPassword2": newpass,
- "crewlinkService": "changePassword",
- "crewlinkOperation": "changePassword",
- "change": "Change"
- });
- var infomsg = parse(res.data).querySelector(".infoMsg")?.text;
- var msg = parse(res.data).querySelector(".errMsg")?.text;
- var errormsg = parse(res.data).querySelector("h1.error")?.text;
- String? error;
- if (res.statusCode == 302) {
- if (!loginfirst) {
- return await changePass(newpass: newpass, loginfirst: true);
- }
- } else if (res.statusCode == 200) {
- error = null;
- } else {
- error = res.statusMessage;
- }
- return {
- 'error': error,
- 'data': {"info": infomsg, "msg": msg, "error": errormsg},
- 'meta': {
- "user": storedusername,
- "pass": storedpassword,
- "statuscode": res.statusCode
- }
- };
- }
- Future logout() async {
- var res = await _dio.get("/closeSession.jsp");
- storedusername = "";
- storedpassword = "";
- String? error;
- if (res.statusCode == 200) {
- error = null;
- } else {
- error = res.statusMessage;
- }
- log(res.toString());
- return {
- 'error': error,
- 'data': {},
- 'meta': {
- "user": storedusername,
- "pass": storedpassword,
- "statuscode": res.statusCode
- }
- };
- }
- Future notif(
- {bool download = false,
- required String fileid,
- CancelToken? cancelToken,
- ProgressCallback? progressCallback,
- bool loginfirst = false}) async {
- if (loginfirst) {
- var x = await login();
- if ((x["data"]["logged"] ?? false) == false) return x;
- }
- var res = await _dio.get(
- "/clApp?crewlinkService=notification&crewlinkOperation=default&crewlinkSourcePage=spCrew");
- String? pdflink = (RegExp(
- r"(?<='js\/pdfjs\/web\/viewer\.html\?file=).+.pdf?(?=')",
- dotAll: true)
- .stringMatch(res.data));
- String? msg = parse(res.data).querySelector(".msgDetails")?.text;
- // String fileid =
- // "${(await getApplicationDocumentsDirectory()).path}/${DateFormat("yyyyMMddHHmm").format(DateTime.now())}_${storedusername}_notif.pdf";
- String? error;
- if (res.statusCode == 302) {
- if (!loginfirst) {
- return await notif(
- download: download,
- fileid: fileid,
- cancelToken: cancelToken,
- progressCallback: progressCallback,
- loginfirst: true);
- }
- } else if (res.statusCode == 200) {
- error = null;
- if (download && pdflink != null) {
- await _dio.download(
- "${Uri.parse(realUrl).scheme}://${Uri.parse(realUrl).host}$pdflink",
- fileid,
- );
- }
- } else {
- error = res.statusMessage;
- }
- return {
- 'error': error,
- 'data': {
- "pdflink": pdflink,
- "msg": msg,
- ...pdflink != null ? {"id": fileid} : {}
- },
- 'meta': {
- "user": storedusername,
- "pass": storedpassword,
- "statuscode": res.statusCode
- }
- };
- }
- Future confirmNotif({bool loginfirst = false}) async {
- if (loginfirst) {
- var x = await login();
- if ((x["data"]["logged"] ?? false) == false) return x;
- }
- var res = await _dio.post("/clApp", data: {
- 'crewlinkService': 'notification',
- 'crewlinkOperation': 'confirmNotif',
- });
- var msg = parse(res.data).querySelector(".errMsg")?.text;
- var errormsg = parse(res.data).querySelector("h1.error")?.text;
- String? error;
- if (res.statusCode == 302) {
- if (!loginfirst) return await confirmNotif(loginfirst: true);
- } else if (res.statusCode == 200) {
- error = null;
- } else {
- error = res.statusMessage;
- }
- // print("==============");
- // print({
- // 'error': error,
- // 'data': {"msg": msg, "error": errormsg},
- // 'meta': {
- // "user": storedusername,
- // "pass": storedpassword,
- // "statuscode": res.statusCode
- // }
- // });
- // print("==============");
- return {
- 'error': error,
- 'data': {"msg": msg, "error": errormsg},
- 'meta': {
- "user": storedusername,
- "pass": storedpassword,
- "statuscode": res.statusCode
- }
- };
- }
- bool credSaved() {
- return (Hive.box("profile").get("crewlink_user", defaultValue: "") != "") &&
- (Hive.box("profile").get("crewlink_pass", defaultValue: "") != "");
- }
- String storedusername = "";
- String storedpassword = "";
- bool get logged => storedusername != "" && storedpassword != "";
- String rostermin = "";
- String rostermax = "";
- String showcrewmin = "";
- String showcrewmax = "";
- Map<String, dynamic> decodeRoster(String pdffile) {
- return _decodeRoster(pdffile);
- }
- Map<String, dynamic> _decodeRoster(String pdffile) {
- // try {
- const weekdays = "Mon|Tue|Wed|Thu|Fri|Sat|Sun";
- const monthday = '[0-3]\\d';
- const month = "Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec";
- const date = "$monthday($month)[0-5]\\d";
- const station = "[A-Z]{3}";
- const al = "[A-Z]{2}";
- const fnum = "\\d{1,4}[A-Z^R]?";
- const actype = "\\d{2}[A-Z0-9]";
- const label = "(OFF|[A-Z]{2,}|[A-Z]+([0-9?]))";
- const time = "[0-2]\\d[0-5]\\d";
- PdfDocument document =
- PdfDocument(inputBytes: File(pdffile).readAsBytesSync());
- var text = PdfTextExtractor(document).extractText(layoutText: true);
- document.dispose();
- text = text.replaceAll("\r\n", "#");
- // var text = ros.replaceAll("\n", "#");
- Map info = {};
- var d = RegExp(r'for(\d+)(.+?),(.+?)#').firstMatch(text);
- info["tlc"] = d?.group(1);
- info["lname"] = d?.group(2);
- info["fname"] = d?.group(3);
- d = RegExp(
- r'NetLine/Crew\((.+?)\)printedbyCREWLINK(.{7})(\d\d:\d\d)Page\d+#')
- .firstMatch(text);
- info["date"] = d?.group(2);
- info["time"] = d?.group(3);
- d = RegExp(r'Period:(.{7})-(.{7})#').firstMatch(text);
- info["startdate"] = d?.group(1);
- info["enddate"] = d?.group(2);
- String header =
- RegExp("(?<=Period:$date-$date#)(.*?)(?=dateHdutyRdeparrACinfo)")
- .stringMatch(text) ??
- "";
- String body = text.replaceAll(
- RegExp(
- "Individualdutyplan(.+?)${RegExp.escape(header)}(dateHdutyRdeparrACinfo#dateHdutyRdeparrACinfo#dateHdutyRdeparrACinfo#)?"),
- "");
- // String footer = RegExp("(Flighttime.*)\$").stringMatch(body) ?? "";
- String onlyprog = RegExp("^(.*?)(?=Flighttime)").stringMatch(body) ?? "";
- onlyprog = onlyprog.replaceAllMapped(
- RegExp("(?:$weekdays)$monthday.+?(?=(($weekdays)$monthday)|\$)"),
- (m) => "${m.group(0)}\n");
- const ground =
- "(?<label>(?:SR|$label(?=R)|$label)?)(?<req>R)?(?<dep>$station)(?<hdep>$time)(?<hdes>$time)(?<actype>$actype?)?";
- const checkin = "C/I(?<station>$station)(?<time>$time)";
- const checkout = "C/O";
- const checkoutData = "(?<time>$time)(?<station>$station)";
- const flight =
- "(?<al>$al?)(?<fnum>$fnum?)(?<fltday>\\/$monthday)?(?<req>R)?(?<dep>$station?)(?<hdep>$time?)(?<hdes>$time?)(?<des>$station?)(?<actype>$actype?)";
- const dhflight =
- "DH\\/(?<al>$al?)(?<fnum>$fnum?)(?<fltday>\\/$monthday)?(?<req>R)?(?<dep>$station?)(?<hdep>$time?)(?<hdes>$time?)(?<des>$station?)";
- const dhlimo =
- "(?<label>$label?)(?<req>R)?(?<dep>$station?)(?<hdep>$time?)(?<hdes>$time?)(?<des>$station?)";
- const credit = "\\[Credit(?<credit>\\d+\\:\\d{2}?)\\]";
- const wholeday = "(?<label>$label)(?<req>R)?(?<dep>$station)";
- const changed = "CHANGED";
- var linedate = _ddmmmyy2date(info["startdate"]);
- Map<String, dynamic> liste = {
- "changed": changed,
- "checkin": checkin,
- "flight": flight,
- "dhflight": dhflight,
- "dhlimo": dhlimo,
- "ground": ground,
- "checkout": checkout,
- "credit": credit,
- "wholeday": wholeday,
- };
- Map<String, List<Map<String, dynamic>>> roster = {};
- for (var line in onlyprog.split("\n")..remove("")) {
- // log("... decoding $line");
- // var dateblock = RegExp("(($weekdays)$monthday)").stringMatch(line);
- // log(dateblock.toString());
- while (roster.keys.contains(_date2ymd(linedate))) {
- linedate = linedate.add(const Duration(days: 1));
- }
- var details = line.replaceAll(RegExp("($weekdays)$monthday"), "");
- // log("... decoding $details");
- List<Map<String, dynamic>> dayduty = [];
- //log(details);
- var elements = details.split("#");
- // log("${elements.length} $elements");
- for (var i = 0;
- (i < elements.length - 1) ||
- (i < elements.length && elements.last != "");
- i++) {
- var e = elements[i];
- bool decoded = false;
- String? remark;
- // log("_______ $i __el: $e");
- for (var dutytype in liste.keys) {
- if (RegExp(liste[dutytype]).hasMatch(e)) {
- late RegExpMatch? res;
- if (dutytype == "checkout" && i + 1 < elements.length) {
- res = RegExp(checkoutData).firstMatch(elements[i + 1]);
- i++;
- } else {
- res = RegExp(liste[dutytype]).firstMatch(e);
- }
- if (["flight", "dhflight", "ground", "dhlimo"].contains(dutytype) &&
- i + 1 < elements.length &&
- !liste.values.any((r) => RegExp(r).hasMatch(elements[i + 1]))) {
- remark = elements[i + 1];
- i++;
- }
- // log("_________$dutytype ${res?.groupNames.map((name) => "$name: ${res?.namedGroup(name)}")}");
- dayduty.add({
- "type": dutytype,
- "data": res?.groupNames.toList().fold(
- {},
- (Map t, n) => t
- ..addAll({
- n: res?.namedGroup(n),
- if (remark != null) ...{"remark": remark}
- })) ??
- {}
- });
- decoded = true;
- break;
- }
- }
- if (!decoded) {
- if (e.isNotEmpty && e != "X") {
- log("__unknown: $e");
- dayduty.add({
- "type": "unknown",
- "data": {"unknown": e.trim()}
- });
- }
- }
- }
- roster[_date2ymd(linedate)] = dayduty;
- //log("$dateblock ${_date2ymd(linedate)} $dayduty");
- }
- return {
- ...{"info": info},
- ...{"roster": roster}
- };
- // } catch (e) {
- // log("crewlinkapi: decoderoster: ${e.toString()}");
- // return {};
- // }
- }
- DateTime _ddmmmyy2date(String date) {
- return DateFormat("ddMMMyy").parseUTC(date);
- }
- String _date2ymd(DateTime date) {
- return DateFormat("y-MM-dd").format(date);
- }
- }
|