diff --git a/application/models/Vucc.php b/application/models/Vucc.php index 4163de860..e31c3b532 100644 --- a/application/models/Vucc.php +++ b/application/models/Vucc.php @@ -27,69 +27,141 @@ class VUCC extends CI_Model * Builds the array to display worked/confirmed vucc on award page */ function fetchVucc($data) { - $totalGridConfirmed = array(); - $totalGridWorked = array(); + // Use associative arrays for O(1) lookups instead of O(n) in_array() + $totalGridWorked = []; + $totalGridConfirmed = []; + $workedGrids = []; + $confirmedGrids = []; - foreach($data['worked_bands'] as $band) { + // Create a lookup array for valid bands + $validBands = array_flip($data['worked_bands']); - // Getting all the worked grids - $col_gridsquare_worked = $this->get_vucc_summary($band, 'none'); + // Get combined data (2 queries instead of 4 per band) + $combinedData = $this->get_vucc_combined_data_all_bands(); + $combinedData2 = $this->get_vucc_combined_data_sat(); - $workedGridArray = array(); - foreach ($col_gridsquare_worked as $workedgrid) { - array_push($workedGridArray, $workedgrid['gridsquare']); - if(!in_array($workedgrid['gridsquare'], $totalGridWorked)){ - array_push($totalGridWorked, $workedgrid['gridsquare']); + // Process col_gridsquare data + if (!empty($combinedData['gridsquare'])) { + foreach ($combinedData['gridsquare'] as $row) { + $grid = $row['gridsquare']; + $band = $row['col_band']; + + // Skip if this band is not in our requested bands list + if (!isset($validBands[$band])) { + continue; } - } - $col_vucc_grids_worked = $this->get_vucc_summary_col_vucc($band, 'none'); + // Always add to worked + $totalGridWorked[$grid] = true; + if (!isset($workedGrids[$band][$grid])) { + $workedGrids[$band][$grid] = true; + } - foreach ($col_vucc_grids_worked as $gridSplit) { - $grids = explode(",", $gridSplit['col_vucc_grids']); - foreach($grids as $key) { - $grid_four = strtoupper(substr(trim($key),0,4)); - - if(!in_array($grid_four, $workedGridArray)){ - array_push($workedGridArray, $grid_four); - } - - if(!in_array($grid_four, $totalGridWorked)){ - array_push($totalGridWorked, $grid_four); + // Add to confirmed if flagged + if ($row['confirmed']) { + $totalGridConfirmed[$grid] = true; + if (!isset($confirmedGrids[$band][$grid])) { + $confirmedGrids[$band][$grid] = true; } } } + } - // Getting all the confirmed grids - $col_gridsquare_confirmed = $this->get_vucc_summary($band, 'both'); + // Process col_vucc_grids data + if (!empty($combinedData['vucc_grids'])) { + foreach ($combinedData['vucc_grids'] as $row) { + $grids = explode(",", $row['col_vucc_grids']); + $band = $row['col_band']; - $confirmedGridArray = array(); - foreach ($col_gridsquare_confirmed as $confirmedgrid) { - array_push($confirmedGridArray, $confirmedgrid['gridsquare']); - if(!in_array($confirmedgrid['gridsquare'], $totalGridConfirmed)){ - array_push($totalGridConfirmed, $confirmedgrid['gridsquare']); + // Skip if this band is not in our requested bands list + if (!isset($validBands[$band])) { + continue; } - } - $col_vucc_grids_confirmed = $this->get_vucc_summary_col_vucc($band, 'both'); + foreach ($grids as $key) { + $grid_four = strtoupper(substr(trim($key), 0, 4)); - foreach ($col_vucc_grids_confirmed as $gridSplit) { - $grids = explode(",", $gridSplit['col_vucc_grids']); - foreach($grids as $key) { - $grid_four = strtoupper(substr(trim($key),0,4)); - - if(!in_array($grid_four, $confirmedGridArray)){ - array_push($confirmedGridArray, $grid_four); + // Always add to worked + $totalGridWorked[$grid_four] = true; + if (!isset($workedGrids[$band][$grid_four])) { + $workedGrids[$band][$grid_four] = true; } - if(!in_array($grid_four, $totalGridConfirmed)){ - array_push($totalGridConfirmed, $grid_four); + // Add to confirmed if flagged + if ($row['confirmed']) { + $totalGridConfirmed[$grid_four] = true; + if (!isset($confirmedGrids[$band][$grid_four])) { + $confirmedGrids[$band][$grid_four] = true; + } } } } + } - $vuccArray[$band]['worked'] = count($workedGridArray); - $vuccArray[$band]['confirmed'] = count($confirmedGridArray); + // Process col_gridsquare data + if (!empty($combinedData2['gridsquare'])) { + foreach ($combinedData2['gridsquare'] as $row) { + $grid = $row['gridsquare']; + $band = $row['col_band']; + + // Skip if this band is not in our requested bands list + if (!isset($validBands[$band])) { + continue; + } + + // Always add to worked + $totalGridWorked[$grid] = true; + if (!isset($workedGrids[$band][$grid])) { + $workedGrids[$band][$grid] = true; + } + + // Add to confirmed if flagged + if ($row['confirmed']) { + $totalGridConfirmed[$grid] = true; + if (!isset($confirmedGrids[$band][$grid])) { + $confirmedGrids[$band][$grid] = true; + } + } + } + } + + // Process col_vucc_grids data + if (!empty($combinedData2['vucc_grids'])) { + foreach ($combinedData2['vucc_grids'] as $row) { + $grids = explode(",", $row['col_vucc_grids']); + $band = $row['col_band']; + + // Skip if this band is not in our requested bands list + if (!isset($validBands[$band])) { + continue; + } + + foreach ($grids as $key) { + $grid_four = strtoupper(substr(trim($key), 0, 4)); + + // Always add to worked + $totalGridWorked[$grid_four] = true; + if (!isset($workedGrids[$band][$grid_four])) { + $workedGrids[$band][$grid_four] = true; + } + + // Add to confirmed if flagged + if ($row['confirmed']) { + $totalGridConfirmed[$grid_four] = true; + if (!isset($confirmedGrids[$band][$grid_four])) { + $confirmedGrids[$band][$grid_four] = true; + } + } + } + } + } + + + // Build the result array with counts per band + $vuccArray = []; + foreach ($data['worked_bands'] as $band) { + $vuccArray[$band]['worked'] = isset($workedGrids[$band]) ? count($workedGrids[$band]) : 0; + $vuccArray[$band]['confirmed'] = isset($confirmedGrids[$band]) ? count($confirmedGrids[$band]) : 0; } $vuccArray['All']['worked'] = count($totalGridWorked); @@ -102,106 +174,86 @@ class VUCC extends CI_Model return $vuccArray; } - /* - * Gets the grid from col_vucc_grids - * $band = the band chosen - * $confirmationMethod - qsl, lotw or both, use anything else to skip confirmed + /* + * Makes a list of all gridsquares on chosen band with info about lotw and qsl + * Optimized to fetch all callsigns in a single query instead of one per grid */ - function get_vucc_summary_col_vucc($band, $confirmationMethod) { + function vucc_details($band, $type) { + // Get combined data for the specific band + $bandData = $this->get_vucc_band_data($band); - if (!$this->logbooks_locations_array) { - return null; + if (empty($bandData['gridsquare']) && empty($bandData['vucc_grids'])) { + return 0; } - $location_list = "'".implode("','",$this->logbooks_locations_array)."'"; + $vuccBand = []; - $sql = "select distinct col_vucc_grids - from " . $this->config->item('table_name') . - " where station_id in (" . $location_list . ")" . - " and col_vucc_grids <> '' "; + // Process col_gridsquare data + foreach ($bandData['gridsquare'] as $row) { + $grid = $row['gridsquare']; + $qsl = $row['qsl_confirmed'] ? 'Y' : ''; + $lotw = $row['lotw_confirmed'] ? 'Y' : ''; + $confirmed = $row['confirmed']; - if ($confirmationMethod == 'both') { - $sql .= " and (col_qsl_rcvd='Y' or col_lotw_qsl_rcvd='Y')"; - } - else if ($confirmationMethod == 'qsl') { - $sql .= " and col_qsl_rcvd='Y'"; - } - else if ($confirmationMethod == 'lotw') { - $sql .= " and col_lotw_qsl_rcvd='Y'"; - } + // Filter based on type + if ($type == 'worked' && $confirmed) { + continue; // Skip confirmed grids when showing only worked + } + if ($type == 'confirmed' && !$confirmed) { + continue; // Skip worked grids when showing only confirmed + } - if ($band != 'All') { - if ($band == 'SAT') { - $sql .= " and col_prop_mode ='" . $band . "'"; + if (!isset($vuccBand[$grid])) { + $vuccBand[$grid]['qsl'] = $qsl; + $vuccBand[$grid]['lotw'] = $lotw; } else { - $sql .= " and col_prop_mode !='SAT'"; - $sql .= " and col_band ='" . $band . "'"; + // Update confirmation status if already exists + if ($qsl) $vuccBand[$grid]['qsl'] = $qsl; + if ($lotw) $vuccBand[$grid]['lotw'] = $lotw; } } - $query = $this->db->query($sql); - return $query->result_array(); - } + // Process col_vucc_grids data + foreach ($bandData['vucc_grids'] as $row) { + $grids = explode(",", $row['col_vucc_grids']); + $qsl = $row['qsl_confirmed'] ? 'Y' : ''; + $lotw = $row['lotw_confirmed'] ? 'Y' : ''; + $confirmed = $row['confirmed']; - /* - * Gets the grid from col_gridsquare - * $band = the band chosen - * $confirmationMethod - qsl, lotw or both, use anything else to skip confirmed - */ - function get_vucc_summary($band, $confirmationMethod) { - if (!$this->logbooks_locations_array) { - return null; - } + foreach ($grids as $key) { + $grid_four = strtoupper(substr(trim($key), 0, 4)); - $location_list = "'".implode("','",$this->logbooks_locations_array)."'"; + // Filter based on type + if ($type == 'worked' && $confirmed) { + continue; // Skip confirmed grids when showing only worked + } + if ($type == 'confirmed' && !$confirmed) { + continue; // Skip worked grids when showing only confirmed + } - $sql = "select distinct upper(substring(log.col_gridsquare, 1, 4)) gridsquare - from " . $this->config->item('table_name') . " log". - " inner join bands b on (b.band = log.col_band) ". - " where log.station_id in (" . $location_list . ")" . - " and log.col_gridsquare <> ''"; + if (!isset($vuccBand[$grid_four])) { + $vuccBand[$grid_four]['qsl'] = $qsl; + $vuccBand[$grid_four]['lotw'] = $lotw; + } else { + // Update confirmation status if already exists + if ($qsl) $vuccBand[$grid_four]['qsl'] = $qsl; + if ($lotw) $vuccBand[$grid_four]['lotw'] = $lotw; + } + } + } - if (($band == 'SAT') || ($band == 'All')) { - $sql.=" and b.bandgroup in ('vhf','uhf','shf','sat')"; - } + // Get all callsigns for all grids in a SINGLE query + $gridCallsigns = $this->get_grid_callsigns_batch(array_keys($vuccBand), $band); - if ($confirmationMethod == 'both') { - $sql .= " and (log.col_qsl_rcvd='Y' or log.col_lotw_qsl_rcvd='Y')"; - } else if ($confirmationMethod == 'qsl') { - $sql .= " and log.col_qsl_rcvd='Y'"; - } else if ($confirmationMethod == 'lotw') { - $sql .= " and log.col_lotw_qsl_rcvd='Y'"; - } - - if ($band != 'All') { - if ($band == 'SAT') { - $sql .= " and log.col_prop_mode ='" . $band . "'"; - } else { - $sql .= " and log.col_prop_mode !='SAT'"; - $sql .= " and log.col_band ='" . $band . "'"; - } - } else { - $sql .= " and log.col_prop_mode !='SAT'"; - } - $query = $this->db->query($sql); - - return $query->result_array(); - } - - /* - * Makes a list of all gridsquares on chosen band with info about lotw and qsl - */ - function vucc_details($band, $type) { - - if ($type == 'worked') { - $workedGridArray = $this->getWorkedGridsList($band, 'none'); - $vuccBand = $this->removeConfirmedGrids($band, $workedGridArray); - } else if ($type == 'confirmed') { - $workedGridArray = $this->getWorkedGridsList($band, 'both'); - $vuccBand = $this->markConfirmedGrids($band, $workedGridArray); - } else { - $workedGridArray = $this->getWorkedGridsList($band, 'none'); - $vuccBand = $this->markConfirmedGrids($band, $workedGridArray); + // Add callsign details for each grid from the batched result + foreach ($vuccBand as $grid => $data) { + $callsignlist = ''; + if (isset($gridCallsigns[$grid])) { + foreach ($gridCallsigns[$grid] as $call) { + $callsignlist .= $call . '
'; + } + } + $vuccBand[$grid]['call'] = $callsignlist; } if (!isset($vuccBand)) { @@ -212,60 +264,141 @@ class VUCC extends CI_Model } } - function removeConfirmedGrids($band, $workedGridArray) { - $vuccDataQsl = $this->get_vucc_summary($band, 'qsl'); - - foreach ($vuccDataQsl as $grid) { - if (($key = array_search($grid['gridsquare'], $workedGridArray)) !== false) { - unset($workedGridArray[$key]); - } + /* + * Fetches callsigns for multiple grids in a single query + * Returns array indexed by 4-character grid with list of callsigns + */ + private function get_grid_callsigns_batch($grids, $band) { + if (empty($grids) || !$this->logbooks_locations_array) { + return []; } - $vuccDataLotw = $this->get_vucc_summary($band, 'lotw'); + $location_list = "'" . implode("','", $this->logbooks_locations_array) . "'"; + $bindings = array(); - foreach ($vuccDataLotw as $grid) { - if (($key = array_search($grid['gridsquare'], $workedGridArray)) !== false) { - unset($workedGridArray[$key]); - } - } - - $col_vucc_grids_confirmed_qsl = $this->get_vucc_summary_col_vucc($band, 'lotw'); - - foreach ($col_vucc_grids_confirmed_qsl as $gridSplit) { - $grids = explode(",", $gridSplit['col_vucc_grids']); - foreach($grids as $key) { - $grid_four = strtoupper(substr(trim($key),0,4)); - if (($key = array_search($grid_four, $workedGridArray)) !== false) { - unset($workedGridArray[$key]); - } - } - } - - $col_vucc_grids_confirmed_lotw = $this->get_vucc_summary_col_vucc($band, 'qsl'); - - foreach ($col_vucc_grids_confirmed_lotw as $gridSplit) { - $grids = explode(",", $gridSplit['col_vucc_grids']); - foreach($grids as $key) { - $grid_four = strtoupper(substr(trim($key),0,4)); - if (($key = array_search($grid_four, $workedGridArray)) !== false) { - unset($workedGridArray[$key]); - } - } - } - foreach ($workedGridArray as $grid) { - $result = $this->grid_detail($grid, $band); - $callsignlist = ''; - foreach($result->result() as $call) { - $callsignlist .= $call->COL_CALL . '
'; - } - $vuccBand[$grid]['call'] = $callsignlist; - } - - if (isset($vuccBand)) { - return $vuccBand; + // Build band condition + if ($band == 'SAT') { + $bandCondition = " and col_prop_mode = 'SAT'"; } else { - return null; + $bandCondition = " and col_prop_mode != 'SAT' and col_band = ?"; + $bindings[] = $band; } + + // Fetch all QSOs for this band - we'll filter by grids in PHP + // This is much more efficient than one query per grid + $sql = "SELECT COL_CALL, col_gridsquare, col_vucc_grids + FROM " . $this->config->item('table_name') . " + WHERE station_id IN (" . $location_list . ") + AND (col_gridsquare <> '' OR col_vucc_grids <> '')" + . $bandCondition; + + $query = $this->db->query($sql, $bindings); + $result = $query->result_array(); + + // Group callsigns by grid in PHP + $gridCallsigns = []; + $gridsLookup = array_flip($grids); // For O(1) lookups + + foreach ($result as $row) { + // Process col_gridsquare + if (!empty($row['col_gridsquare'])) { + $grid_four = strtoupper(substr($row['col_gridsquare'], 0, 4)); + if (isset($gridsLookup[$grid_four])) { + if (!isset($gridCallsigns[$grid_four])) { + $gridCallsigns[$grid_four] = []; + } + // Avoid duplicate callsigns for the same grid + if (!in_array($row['COL_CALL'], $gridCallsigns[$grid_four])) { + $gridCallsigns[$grid_four][] = $row['COL_CALL']; + } + } + } + + // Process col_vucc_grids (comma-separated list) + if (!empty($row['col_vucc_grids'])) { + $vuccGrids = explode(",", $row['col_vucc_grids']); + foreach ($vuccGrids as $vuccGrid) { + $grid_four = strtoupper(substr(trim($vuccGrid), 0, 4)); + if (isset($gridsLookup[$grid_four])) { + if (!isset($gridCallsigns[$grid_four])) { + $gridCallsigns[$grid_four] = []; + } + // Avoid duplicate callsigns for the same grid + if (!in_array($row['COL_CALL'], $gridCallsigns[$grid_four])) { + $gridCallsigns[$grid_four][] = $row['COL_CALL']; + } + } + } + } + } + + return $gridCallsigns; + } + + /* + * Fetches VUCC data for a specific band with QSL/LoTW confirmation details + * Returns data in a single query per band + */ + private function get_vucc_band_data($band) { + if (!$this->logbooks_locations_array) { + return ['gridsquare' => [], 'vucc_grids' => []]; + } + + $results = ['gridsquare' => [], 'vucc_grids' => []]; + + $location_list = "'" . implode("','", $this->logbooks_locations_array) . "'"; + + $bindings1 = array(); + + if ($band == 'SAT') { + $bandCondition1 = " and log.col_prop_mode = 'SAT'"; + } else { + $bandCondition1 = " and log.col_prop_mode != 'SAT' and log.col_band = ?"; + $bindings1[] = $band; + } + + $sql1 = "SELECT + DISTINCT UPPER(SUBSTRING(col_gridsquare, 1, 4)) as gridsquare, + MAX(CASE WHEN col_qsl_rcvd='Y' THEN 1 ELSE 0 END) as qsl_confirmed, + MAX(CASE WHEN col_lotw_qsl_rcvd='Y' THEN 1 ELSE 0 END) as lotw_confirmed, + MAX(CASE WHEN (col_qsl_rcvd='Y' OR col_lotw_qsl_rcvd='Y') THEN 1 ELSE 0 END) as confirmed + FROM " . $this->config->item('table_name') . " log + WHERE log.station_id IN (" . $location_list . ") + AND log.col_gridsquare <> ''" + . $bandCondition1 . " + GROUP BY UPPER(SUBSTRING(col_gridsquare, 1, 4))"; + + $query1 = $this->db->query($sql1, $bindings1); + if ($query1->num_rows() > 0) { + $results['gridsquare'] = $query1->result_array(); + } + + if ($band == 'SAT') { + $bandCondition2 = " and col_prop_mode = ?"; + $bindings2[] = $band; + } else { + $bandCondition2 = " and col_prop_mode != ? and col_band = ?"; + $bindings2[] = 'SAT'; + $bindings2[] = $band; + } + + $sql2 = "SELECT + DISTINCT col_vucc_grids, + MAX(CASE WHEN col_qsl_rcvd='Y' THEN 1 ELSE 0 END) as qsl_confirmed, + MAX(CASE WHEN col_lotw_qsl_rcvd='Y' THEN 1 ELSE 0 END) as lotw_confirmed, + MAX(CASE WHEN (col_qsl_rcvd='Y' OR col_lotw_qsl_rcvd='Y') THEN 1 ELSE 0 END) as confirmed + FROM " . $this->config->item('table_name') . " + WHERE station_id IN (" . $location_list . ") + AND col_vucc_grids <> ''" + . $bandCondition2 . " + GROUP BY col_vucc_grids"; + + $query2 = $this->db->query($sql2, $bindings2); + if ($query2->num_rows() > 0) { + $results['vucc_grids'] = $query2->result_array(); + } + + return $results; } function grid_detail($gridsquare, $band) { @@ -287,142 +420,50 @@ class VUCC extends CI_Model return $this->db->query($sql); } - function markConfirmedGrids($band, $workedGridArray) { - foreach ($workedGridArray as $grid) { - $vuccBand[$grid]['qsl'] = ''; - $vuccBand[$grid]['lotw'] = ''; - } - - $vuccDataQsl = $this->get_vucc_summary($band, 'qsl'); - - foreach ($vuccDataQsl as $grid) { - $vuccBand[$grid['gridsquare']]['qsl'] = 'Y'; - } - - $vuccDataLotw = $this->get_vucc_summary($band, 'lotw'); - - foreach ($vuccDataLotw as $grid) { - $vuccBand[$grid['gridsquare']]['lotw'] = 'Y'; - } - - $col_vucc_grids_confirmed_qsl = $this->get_vucc_summary_col_vucc($band, 'lotw'); - - foreach ($col_vucc_grids_confirmed_qsl as $gridSplit) { - $grids = explode(",", $gridSplit['col_vucc_grids']); - foreach($grids as $key) { - $grid_four = strtoupper(substr(trim($key),0,4)); - $vuccBand[$grid_four]['lotw'] = 'Y'; - } - } - - $col_vucc_grids_confirmed_lotw = $this->get_vucc_summary_col_vucc($band, 'qsl'); - - foreach ($col_vucc_grids_confirmed_lotw as $gridSplit) { - $grids = explode(",", $gridSplit['col_vucc_grids']); - foreach($grids as $key) { - $grid_four = strtoupper(substr(trim($key),0,4)); - $vuccBand[$grid_four]['qsl'] = 'Y'; - } - } - - return $vuccBand; - } - - function getWorkedGridsList($band, $confirmationMethod) { - - $col_gridsquare_worked = $this->get_vucc_summary($band, $confirmationMethod); - - $workedGridArray = array(); - foreach ($col_gridsquare_worked as $workedgrid) { - array_push($workedGridArray, $workedgrid['gridsquare']); - } - - $col_vucc_grids_worked = $this->get_vucc_summary_col_vucc($band, $confirmationMethod); - - foreach ($col_vucc_grids_worked as $gridSplit) { - $grids = explode(",", $gridSplit['col_vucc_grids']); - foreach($grids as $key) { - $grid_four = strtoupper(substr(trim($key),0,4)); - - if(!in_array($grid_four, $workedGridArray)){ - array_push($workedGridArray, $grid_four); - } - } - } - - return $workedGridArray; - } - - private function get_vucc_combined_data($band = 'All') { + /* + * Fetches VUCC data for ALL bands in 2 queries (optimized) + * Similar approach to CQ model's getCqZoneData() + * Returns data with band information included for processing + */ + private function get_vucc_combined_data_all_bands() { if (!$this->logbooks_locations_array) { return ['gridsquare' => [], 'vucc_grids' => []]; } $results = ['gridsquare' => [], 'vucc_grids' => []]; - $inPlaceholders = str_repeat('?,', count($this->logbooks_locations_array) - 1) . '?'; - - // Query 1: Get col_gridsquare data with worked/confirmed status - $bindings1 = array_merge($this->logbooks_locations_array); - $bandCondition1 = ''; - - if ($band != 'All') { - if ($band == 'SAT') { - $bandCondition1 = " and log.col_prop_mode = ?"; - $bindings1[] = $band; - } else { - $bandCondition1 = " and log.col_prop_mode != ? and log.col_band = ?"; - $bindings1[] = 'SAT'; - $bindings1[] = $band; - } - } else { - $bandCondition1 = " and log.col_prop_mode != ?"; - $bindings1[] = 'SAT'; - } + // Query 1: Get col_gridsquare data for ALL bands with worked/confirmed status + // GROUP BY both gridsquare and band to get per-band statistics + $location_list = "'" . implode("','", $this->logbooks_locations_array) . "'"; $sql1 = "SELECT DISTINCT UPPER(SUBSTRING(col_gridsquare, 1, 4)) as gridsquare, + col_band, MAX(CASE WHEN (col_qsl_rcvd='Y' OR col_lotw_qsl_rcvd='Y') THEN 1 ELSE 0 END) as confirmed FROM " . $this->config->item('table_name') . " log - INNER JOIN bands b ON (b.band = log.col_band) - WHERE log.station_id IN (" . $inPlaceholders . ") + WHERE log.station_id IN (" . $location_list . ") AND log.col_gridsquare <> '' - AND b.bandgroup IN ('vhf','uhf','shf','sat')" - . $bandCondition1 . " - GROUP BY UPPER(SUBSTRING(col_gridsquare, 1, 4))"; + AND log.col_prop_mode != 'SAT' + GROUP BY UPPER(SUBSTRING(col_gridsquare, 1, 4)), col_band"; - $query1 = $this->db->query($sql1, $bindings1); + $query1 = $this->db->query($sql1); if ($query1->num_rows() > 0) { $results['gridsquare'] = $query1->result_array(); } - // Query 2: Get col_vucc_grids data with worked/confirmed status - // Note: col_vucc_grids has NO band filter when band='All' (includes SAT) - $bindings2 = array_merge($this->logbooks_locations_array); - $bandCondition2 = ''; - - if ($band != 'All') { - if ($band == 'SAT') { - $bandCondition2 = " and col_prop_mode = ?"; - $bindings2[] = $band; - } else { - $bandCondition2 = " and col_prop_mode != ? and col_band = ?"; - $bindings2[] = 'SAT'; - $bindings2[] = $band; - } - } - // When band='All', NO band filter is added (includes all prop_mode including SAT) + // Query 2: Get col_vucc_grids data for ALL bands with worked/confirmed status $sql2 = "SELECT DISTINCT col_vucc_grids, + col_band, MAX(CASE WHEN (col_qsl_rcvd='Y' OR col_lotw_qsl_rcvd='Y') THEN 1 ELSE 0 END) as confirmed FROM " . $this->config->item('table_name') . " - WHERE station_id IN (" . $inPlaceholders . ") - AND col_vucc_grids <> ''" - . $bandCondition2 . " - GROUP BY col_vucc_grids"; + WHERE station_id IN (" . $location_list . ") + AND col_vucc_grids <> '' + AND col_prop_mode != 'SAT' + GROUP BY col_vucc_grids, col_band"; - $query2 = $this->db->query($sql2, $bindings2); + $query2 = $this->db->query($sql2); if ($query2->num_rows() > 0) { $results['vucc_grids'] = $query2->result_array(); } @@ -430,7 +471,58 @@ class VUCC extends CI_Model return $results; } - /* + /* + * Fetches VUCC data for ALL bands in 2 queries (optimized) + * Similar approach to CQ model's getCqZoneData() + * Returns data with band information included for processing + */ + private function get_vucc_combined_data_sat() { + if (!$this->logbooks_locations_array) { + return ['gridsquare' => [], 'vucc_grids' => []]; + } + + $results = ['gridsquare' => [], 'vucc_grids' => []]; + + // Query 1: Get col_gridsquare data for ALL bands with worked/confirmed status + // GROUP BY both gridsquare and band to get per-band statistics + $location_list = "'" . implode("','", $this->logbooks_locations_array) . "'"; + + $sql1 = "SELECT + DISTINCT UPPER(SUBSTRING(col_gridsquare, 1, 4)) as gridsquare, + col_prop_mode as col_band, + MAX(CASE WHEN (col_qsl_rcvd='Y' OR col_lotw_qsl_rcvd='Y') THEN 1 ELSE 0 END) as confirmed + FROM " . $this->config->item('table_name') . " log + WHERE log.station_id IN (" . $location_list . ") + AND log.col_gridsquare <> '' + AND log.col_prop_mode = 'SAT' + GROUP BY UPPER(SUBSTRING(col_gridsquare, 1, 4)), col_prop_mode"; + + $query1 = $this->db->query($sql1); + if ($query1->num_rows() > 0) { + $results['gridsquare'] = $query1->result_array(); + } + + // Query 2: Get col_vucc_grids data for ALL bands with worked/confirmed status + + $sql2 = "SELECT + DISTINCT col_vucc_grids, + col_prop_mode as col_band, + MAX(CASE WHEN (col_qsl_rcvd='Y' OR col_lotw_qsl_rcvd='Y') THEN 1 ELSE 0 END) as confirmed + FROM " . $this->config->item('table_name') . " + WHERE station_id IN (" . $location_list . ") + AND col_vucc_grids <> '' + AND col_prop_mode = 'SAT' + GROUP BY col_vucc_grids, col_prop_mode"; + + $query2 = $this->db->query($sql2); + if ($query2->num_rows() > 0) { + $results['vucc_grids'] = $query2->result_array(); + } + + return $results; + } + + /* * Builds the array to display worked/confirmed vucc on dashboard page */ function fetchVuccSummary($band = 'All') { @@ -475,5 +567,79 @@ class VUCC extends CI_Model return $vuccArray; } + + private function get_vucc_combined_data($band = 'All') { + if (!$this->logbooks_locations_array) { + return ['gridsquare' => [], 'vucc_grids' => []]; + } + + $results = ['gridsquare' => [], 'vucc_grids' => []]; + + $location_list = "'" . implode("','", $this->logbooks_locations_array) . "'"; + + // Query 1: Get col_gridsquare data with worked/confirmed status + $bandCondition1 = ''; + $bindings1 = array(); + + if ($band != 'All') { + if ($band == 'SAT') { + $bandCondition1 = " and log.col_prop_mode = 'SAT'"; + } else { + $bandCondition1 = " and log.col_prop_mode != 'SAT' and log.col_band = ?"; + $bindings1[] = $band; + } + } else { + $bandCondition1 = " and log.col_prop_mode != 'SAT'"; + } + + $sql1 = "SELECT + DISTINCT UPPER(SUBSTRING(col_gridsquare, 1, 4)) as gridsquare, + MAX(CASE WHEN (col_qsl_rcvd='Y' OR col_lotw_qsl_rcvd='Y') THEN 1 ELSE 0 END) as confirmed + FROM " . $this->config->item('table_name') . " log + INNER JOIN bands b ON (b.band = log.col_band) + WHERE log.station_id IN (" . $location_list . ") + AND log.col_gridsquare <> '' + AND b.bandgroup IN ('vhf','uhf','shf','sat')" + . $bandCondition1 . " + GROUP BY UPPER(SUBSTRING(col_gridsquare, 1, 4))"; + + $query1 = $this->db->query($sql1, $bindings1); + if ($query1->num_rows() > 0) { + $results['gridsquare'] = $query1->result_array(); + } + + // Query 2: Get col_vucc_grids data with worked/confirmed status + // Note: col_vucc_grids has NO band filter when band='All' (includes SAT) + $bandCondition2 = ''; + + $bindings2 = array(); + + if ($band != 'All') { + if ($band == 'SAT') { + $bandCondition2 = " and col_prop_mode = 'SAT'"; + } else { + $bandCondition2 = " and col_prop_mode != 'SAT' and col_band = ?"; + $bindings2[] = $band; + } + } + // When band='All', NO band filter is added (includes all prop_mode including SAT) + + $sql2 = "SELECT + DISTINCT col_vucc_grids, + MAX(CASE WHEN (col_qsl_rcvd='Y' OR col_lotw_qsl_rcvd='Y') THEN 1 ELSE 0 END) as confirmed + FROM " . $this->config->item('table_name') . " + WHERE station_id IN (" . $location_list . ") + AND col_vucc_grids <> ''" + . $bandCondition2 . " + GROUP BY col_vucc_grids"; + + $query2 = $this->db->query($sql2, $bindings2); + if ($query2->num_rows() > 0) { + $results['vucc_grids'] = $query2->result_array(); + } + + return $results; + } + } ?>