mirror of
https://github.com/wavelog/wavelog
synced 2026-08-13 18:41:16 -04:00
264 lines
6.9 KiB
PHP
264 lines
6.9 KiB
PHP
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
|
|
|
|
/**
|
|
* AMSAT Rover Award Model
|
|
*
|
|
* Handles data retrieval and point calculation for the AMSAT Rover Award
|
|
*
|
|
* @package Wavelog
|
|
* @subpackage Models
|
|
* @category Awards
|
|
*/
|
|
|
|
class Amsat_rover extends CI_Model {
|
|
|
|
private ?array $mode_map = null;
|
|
|
|
/**
|
|
* Pre-load mode→qrgmode mapping from adif_modes table
|
|
*/
|
|
private function load_mode_map() {
|
|
if ($this->mode_map !== null) return;
|
|
$this->mode_map = [];
|
|
$query = $this->db->query('SELECT mode, submode, qrgmode FROM adif_modes WHERE active = 1');
|
|
if ($query) {
|
|
foreach ($query->result() as $row) {
|
|
$key = strtoupper($row->mode) . '|' . strtoupper($row->submode ?? '');
|
|
$this->mode_map[$key] = strtoupper($row->qrgmode);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get active station profile info for the current user
|
|
*/
|
|
function get_station_info() {
|
|
$this->load->model('stations');
|
|
$home_grid = $this->stations->find_gridsquare() ?? '';
|
|
$home_dxcc = '';
|
|
$station_callsign = '';
|
|
|
|
$query = $this->db->query(
|
|
'SELECT station_dxcc, station_callsign FROM station_profile WHERE user_id = ? AND station_active = 1',
|
|
[$this->session->userdata('user_id')]
|
|
);
|
|
if ($query && $query->num_rows() > 0) {
|
|
$row = $query->row();
|
|
$home_dxcc = $row->station_dxcc ?? '';
|
|
$station_callsign = $row->station_callsign ?? '';
|
|
}
|
|
|
|
return compact('home_grid', 'home_dxcc', 'station_callsign');
|
|
}
|
|
|
|
/**
|
|
* Build confirmation filters from POST data
|
|
*/
|
|
function get_filters() {
|
|
$confirmations = [];
|
|
foreach (['lotw', 'qsl'] as $type) {
|
|
if ($this->input->post($type)) {
|
|
$confirmations[] = $type;
|
|
}
|
|
}
|
|
if (empty($confirmations)) {
|
|
$confirmations = ['lotw', 'qsl'];
|
|
}
|
|
return ['confirmations' => $confirmations];
|
|
}
|
|
|
|
/**
|
|
* Get confirmed satellite QSOs with station profile data
|
|
*
|
|
* @param array $location_ids Station location IDs from logbooks_model
|
|
* @param array $filters Filters including confirmation types
|
|
* @return array QSO data
|
|
*/
|
|
function get_satellite_qsos($location_ids, $filters = []) {
|
|
if (empty($location_ids) || ($location_ids[0] ?? null) === -1) {
|
|
return [];
|
|
}
|
|
|
|
$safe_ids = array_map('intval', $location_ids);
|
|
$safe_ids = array_filter($safe_ids, function($id) { return $id > 0; });
|
|
if (empty($safe_ids)) {
|
|
return [];
|
|
}
|
|
$location_list = implode(',', $safe_ids);
|
|
|
|
$this->load->library('Genfunctions');
|
|
$postdata = [];
|
|
foreach ($filters['confirmations'] ?? ['lotw', 'qsl'] as $type) {
|
|
$postdata[$type] = '1';
|
|
}
|
|
$confirmation_sql = $this->genfunctions->addQslToQuery($postdata);
|
|
$bindings = ['SAT', '2018-01-01'];
|
|
|
|
$table_name = $this->config->item('table_name');
|
|
|
|
$sql = "SELECT
|
|
qso.COL_SAT_NAME,
|
|
qso.COL_MODE,
|
|
qso.COL_SUBMODE,
|
|
qso.COL_LOTW_QSL_RCVD,
|
|
qso.COL_QSL_RCVD,
|
|
qso.COL_TIME_ON,
|
|
qso.COL_CALL,
|
|
qso.COL_DXCC,
|
|
sp.station_gridsquare AS home_grid,
|
|
sp.station_dxcc AS home_dxcc,
|
|
sp.station_callsign AS station_callsign
|
|
FROM {$table_name} qso
|
|
JOIN station_profile sp ON qso.station_id = sp.station_id
|
|
WHERE qso.station_id IN ({$location_list})
|
|
AND qso.COL_PROP_MODE = ?
|
|
AND qso.COL_TIME_ON >= ?
|
|
{$confirmation_sql}
|
|
ORDER BY qso.COL_TIME_ON DESC";
|
|
|
|
try {
|
|
$query = $this->db->query($sql, $bindings);
|
|
if ($query && $query->num_rows() > 0) {
|
|
return $query->result();
|
|
}
|
|
} catch (Exception $e) {
|
|
log_message('error', 'AMSAT Rover Model Error: ' . $e->getMessage());
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
/**
|
|
* Fetch QSOs, calculate activations and summary
|
|
*/
|
|
function get_activations($filters, $station_info) {
|
|
$this->load->model('logbooks_model');
|
|
$locations = $this->logbooks_model->list_logbook_relationships(
|
|
$this->session->userdata('active_station_logbook')
|
|
);
|
|
|
|
$qsos = $this->get_satellite_qsos($locations, $filters);
|
|
$activations = $this->calculate_points(
|
|
$qsos, $station_info['home_dxcc']
|
|
);
|
|
|
|
return [
|
|
'activations' => $activations,
|
|
'summary' => $this->get_summary($activations),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Calculate bonus points from POST data
|
|
*/
|
|
function get_bonus() {
|
|
$bonus = 0;
|
|
$details = [];
|
|
$items = [
|
|
'bonus_social' => ['Social Media Promotion', 5],
|
|
'bonus_photos' => ['Photo Posting', 5],
|
|
'bonus_mm' => ['Maritime Mobile', 10],
|
|
'bonus_journal' => ['AMSAT Journal Article', 15],
|
|
];
|
|
foreach ($items as $field => [$label, $pts]) {
|
|
if ($this->input->post($field)) {
|
|
$bonus += $pts;
|
|
$details[] = " + {$label} ({$pts})";
|
|
}
|
|
}
|
|
return compact('bonus', 'details');
|
|
}
|
|
|
|
/**
|
|
* Calculate points from QSO data
|
|
*
|
|
* Only ONE QSO per grid per mode category per operator DXCC counts.
|
|
*/
|
|
function calculate_points($qsos, $home_dxcc) {
|
|
$results = [];
|
|
$seen = [];
|
|
|
|
if (empty($qsos)) {
|
|
return $results;
|
|
}
|
|
|
|
foreach ($qsos as $qso) {
|
|
$grid = !empty($qso->home_grid) ? strtoupper(trim($qso->home_grid)) : '';
|
|
$grid_4 = substr($grid, 0, 4);
|
|
if (empty($grid_4)) {
|
|
continue;
|
|
}
|
|
|
|
$cat = $this->get_mode_category($qso->COL_MODE, $qso->COL_SUBMODE);
|
|
$key = $grid_4 . '_' . $cat . '_' . ($qso->home_dxcc ?? '');
|
|
if (isset($seen[$key])) {
|
|
continue;
|
|
}
|
|
$seen[$key] = true;
|
|
|
|
$points = match ($cat) { 'FM' => 1, 'Digital' => 3, default => 2 };
|
|
if (!empty($home_dxcc) && !empty($qso->COL_DXCC) && $qso->COL_DXCC != $home_dxcc) {
|
|
$points += 1;
|
|
}
|
|
|
|
$confirmation = 'Unknown';
|
|
if ($qso->COL_LOTW_QSL_RCVD == 'Y') {
|
|
$confirmation = 'LoTW';
|
|
} elseif ($qso->COL_QSL_RCVD == 'Y') {
|
|
$confirmation = 'QSL';
|
|
}
|
|
|
|
$results[] = [
|
|
'my_grid' => $grid_4,
|
|
'call_worked' => $qso->COL_CALL,
|
|
'mode' => strtoupper($qso->COL_MODE ?? ''),
|
|
'mode_category' => $cat,
|
|
'points' => $points,
|
|
'confirmation' => $confirmation,
|
|
'date' => $qso->COL_TIME_ON,
|
|
'satellite' => $qso->COL_SAT_NAME,
|
|
'station_callsign' => $qso->station_callsign ?? '',
|
|
];
|
|
}
|
|
|
|
usort($results, function($a, $b) {
|
|
return strcmp($a['my_grid'], $b['my_grid'])
|
|
?: strcmp($a['mode_category'], $b['mode_category'])
|
|
?: strcmp($a['satellite'] ?? '', $b['satellite'] ?? '');
|
|
});
|
|
|
|
return $results;
|
|
}
|
|
|
|
function get_mode_category($mode, $submode) {
|
|
$mode = strtoupper($mode ?? '');
|
|
if ($mode == 'FM') return 'FM';
|
|
|
|
$this->load_mode_map();
|
|
$submode = strtoupper($submode ?? '');
|
|
$key = $mode . '|' . $submode;
|
|
$qrgmode = $this->mode_map[$key] ?? $this->mode_map[$mode . '|'] ?? null;
|
|
|
|
return $qrgmode == 'DATA' ? 'Digital' : 'Linear';
|
|
}
|
|
|
|
function get_summary($activations) {
|
|
$total = 0;
|
|
$counts = ['FM' => 0, 'Digital' => 0, 'Linear' => 0];
|
|
|
|
foreach ($activations as $act) {
|
|
$total += $act['points'];
|
|
$counts[$act['mode_category']] = ($counts[$act['mode_category']] ?? 0) + 1;
|
|
}
|
|
|
|
return [
|
|
'total_points' => $total,
|
|
'grid_count' => count($activations),
|
|
'fm_count' => $counts['FM'],
|
|
'linear_count' => $counts['Linear'],
|
|
'digital_count' => $counts['Digital'],
|
|
'target' => 25,
|
|
'complete' => $total >= 25,
|
|
];
|
|
}
|
|
}
|