|
|
|
@ -1,6 +1,6 @@ |
|
|
|
import { Injectable } from '@angular/core'; |
|
|
|
import { HttpClient } from '@angular/common/http'; |
|
|
|
import { map, Observable, shareReplay, tap } from 'rxjs'; |
|
|
|
import { concatMap, map, Observable, pipe, shareReplay, tap } from 'rxjs'; |
|
|
|
import { Pokemon, PokemonEncounter } from '../models/pokemon.model'; |
|
|
|
import { environment } from '../../../environments/environment.development'; |
|
|
|
import { comparePfics } from '../utils/pfic-utils'; |
|
|
|
@ -12,41 +12,123 @@ export class PokemonService { |
|
|
|
private apiUrl = environment.apiUrl; |
|
|
|
private pokemonCache: Observable<(Pokemon | null)[][]> | null = null; |
|
|
|
private pokemonGroups: (Pokemon | null)[][] = []; |
|
|
|
private pokemonFormMap: Map<string, Pokemon> = new Map<string, Pokemon>(); |
|
|
|
|
|
|
|
private pokemonFormCache: Observable<(Pokemon)[]> | null = null; |
|
|
|
|
|
|
|
constructor(private http: HttpClient) { } |
|
|
|
|
|
|
|
getPokemonList(): Observable<(Pokemon | null)[][]> { |
|
|
|
getPokemonBoxList(): Observable<(Pokemon | null)[][]> { |
|
|
|
if (this.pokemonCache) { |
|
|
|
return this.pokemonCache; |
|
|
|
} |
|
|
|
|
|
|
|
this.pokemonCache = this.http.get<(any | null)[][]>(`${this.apiUrl}/pokemon`).pipe( |
|
|
|
map(groups => groups.map(group => |
|
|
|
group.map(pokemon => pokemon ? { |
|
|
|
PFIC: pokemon.PFIC, |
|
|
|
Name: pokemon.name, |
|
|
|
Form: pokemon.form_name, |
|
|
|
NationalDex: pokemon.national_dex, |
|
|
|
Generation: pokemon.generation, |
|
|
|
StorableInHome: pokemon.storable_in_home, |
|
|
|
IsBabyForm: pokemon.is_baby_form, |
|
|
|
Encounters: pokemon.encounters || [], |
|
|
|
MarkIcon: pokemon.icon_path, |
|
|
|
MarkName: pokemon.mark_name, |
|
|
|
Image: this.getPokemonImageUrl(pokemon.PFIC), |
|
|
|
IsDefault: pokemon.is_default || false, |
|
|
|
IsCaught: this.caughtPokemon.has(pokemon.PFIC) |
|
|
|
} as Pokemon : null) |
|
|
|
)), |
|
|
|
tap(groups => { |
|
|
|
this.pokemonGroups = groups; // Store the groups for later updates
|
|
|
|
this.pokemonCache = this.getPokemonList().pipe( |
|
|
|
map((pokemonList) => { |
|
|
|
const boxes: (Pokemon | null)[][] = []; |
|
|
|
let currentBox: (Pokemon | null)[] = []; |
|
|
|
let currentGeneration = 0; |
|
|
|
let currentDexNumber = 0; |
|
|
|
let formsGroup: Pokemon[] = []; |
|
|
|
|
|
|
|
for (const pokemon of pokemonList) { |
|
|
|
// Start a new NationalDex group if needed
|
|
|
|
if (pokemon.NationalDex !== currentDexNumber) { |
|
|
|
// If formsGroup has Pokémon, add them to the current box
|
|
|
|
if (formsGroup.length > 0) { |
|
|
|
for (const form of formsGroup) { |
|
|
|
currentBox.push(form); |
|
|
|
if (currentBox.length === 30) { |
|
|
|
boxes.push([...currentBox]); |
|
|
|
currentBox = []; |
|
|
|
} |
|
|
|
} |
|
|
|
formsGroup = []; |
|
|
|
} |
|
|
|
currentDexNumber = pokemon.NationalDex; |
|
|
|
|
|
|
|
// Start a new generation box if needed
|
|
|
|
if (currentGeneration !== pokemon.Generation) { |
|
|
|
if (currentBox.length > 0) { |
|
|
|
while (currentBox.length < 30) { |
|
|
|
currentBox.push(null); |
|
|
|
} |
|
|
|
boxes.push([...currentBox]); |
|
|
|
currentBox = []; |
|
|
|
} |
|
|
|
currentGeneration = pokemon.Generation; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Add the Pokémon form to the group for the current NationalDex
|
|
|
|
formsGroup.push(pokemon); |
|
|
|
} |
|
|
|
|
|
|
|
// Add any remaining forms in the last group
|
|
|
|
for (const form of formsGroup) { |
|
|
|
currentBox.push(form); |
|
|
|
if (currentBox.length === 30) { |
|
|
|
boxes.push([...currentBox]); |
|
|
|
currentBox = []; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Add the last box with padding if needed
|
|
|
|
if (currentBox.length > 0) { |
|
|
|
while (currentBox.length < 30) { |
|
|
|
currentBox.push(null); |
|
|
|
} |
|
|
|
boxes.push(currentBox); |
|
|
|
} |
|
|
|
|
|
|
|
return boxes; |
|
|
|
}), |
|
|
|
// Share the result to cache it for future subscribers
|
|
|
|
shareReplay(1) |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
return this.pokemonCache; |
|
|
|
} |
|
|
|
|
|
|
|
getPokemonList(){ |
|
|
|
if(this.pokemonFormCache) { |
|
|
|
return this.pokemonFormCache; |
|
|
|
} |
|
|
|
this.pokemonFormCache = this.http.get<any[]>(`${this.apiUrl}/pokemon`).pipe( |
|
|
|
map((rows) => rows.map(row => { |
|
|
|
const pkmn = { |
|
|
|
PFIC: row.pfic, |
|
|
|
Name: row.data.name, |
|
|
|
Form: row.data.form_name, |
|
|
|
NationalDex: row.data.national_dex, |
|
|
|
Generation: row.data.generation, |
|
|
|
StorableInHome: row.data.storable_in_home, |
|
|
|
IsBabyForm: row.data.is_baby_form, |
|
|
|
Encounters: row.data.encounters || [], |
|
|
|
MarkIcon: "", |
|
|
|
MarkName: row.data.mark, |
|
|
|
Image: "", |
|
|
|
IsDefault: row.data.is_default || false, |
|
|
|
IsGenderRelevant: row.data.gender_relevant, |
|
|
|
IsCaught: this.caughtPokemon.has(row.PFIC) |
|
|
|
} as Pokemon; |
|
|
|
pkmn.MarkIcon = this.getMarkImgName(pkmn.MarkName) |
|
|
|
pkmn.Image = this.getPokemonImageUrl(pkmn) |
|
|
|
return pkmn; |
|
|
|
}) |
|
|
|
), |
|
|
|
tap(pokemon_list => { |
|
|
|
pokemon_list.forEach(mon => { |
|
|
|
this.pokemonFormMap.set(mon.PFIC, mon); |
|
|
|
}); |
|
|
|
}), |
|
|
|
// Cache the result for future subscribers
|
|
|
|
shareReplay(1) |
|
|
|
); |
|
|
|
|
|
|
|
return this.pokemonFormCache; |
|
|
|
} |
|
|
|
|
|
|
|
getPokemonDetails(pfic: string): Observable<PokemonEncounter[]> { |
|
|
|
return this.http.get<PokemonEncounter[]>(`${this.apiUrl}/pokemon/${pfic}`); |
|
|
|
} |
|
|
|
@ -84,6 +166,10 @@ export class PokemonService { |
|
|
|
return this.caughtPokemon.has(pfic); |
|
|
|
} |
|
|
|
|
|
|
|
getPokemonFromPFIC(pfic:string): Pokemon { |
|
|
|
return this.pokemonFormMap.get(pfic) as Pokemon |
|
|
|
} |
|
|
|
|
|
|
|
updateCaughtStatus(pfic: string, caught: boolean) { |
|
|
|
if (caught) { |
|
|
|
this.caughtPokemon.add(pfic); |
|
|
|
@ -92,8 +178,35 @@ export class PokemonService { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
getPokemonImageUrl(pfic: string): string { |
|
|
|
return `/assets/images/pokemon/${pfic}.png`; |
|
|
|
getPokemonImageUrl(data: Pokemon): string { |
|
|
|
if (data.IsGenderRelevant) { |
|
|
|
return `/assets/images/pokemon/${data.PFIC}.png`; |
|
|
|
} |
|
|
|
const gender_less = data.PFIC.slice(0, -1) + '0' |
|
|
|
return `/assets/images/pokemon/${gender_less}.png`; |
|
|
|
} |
|
|
|
|
|
|
|
getMarkImgName(mark: string): string { |
|
|
|
switch (mark) { |
|
|
|
case "Game Boy": |
|
|
|
return "images/marks/GB_icon_HOME.png" |
|
|
|
case "Markless": |
|
|
|
return "images/marks/Markless_icon_HOME.png" |
|
|
|
case "Kalos": |
|
|
|
return "images/marks/Blue_pentagon_HOME.png" |
|
|
|
case "Let's Go": |
|
|
|
return "images/marks/Let's_Go_icon_HOME.png" |
|
|
|
case "Galar": |
|
|
|
return "images/marks/Galar_symbol_HOME.png" |
|
|
|
case "Sinnoh": |
|
|
|
return "images/marks/BDSP_icon_HOME.png" |
|
|
|
case "Hisui": |
|
|
|
return "images/marks/Arceus_mark_HOME.png" |
|
|
|
case "Paldea": |
|
|
|
return "images/marks/Paldea_icon_HOME.png" |
|
|
|
} |
|
|
|
|
|
|
|
return "images/marks/Markless_icon_HOME.png" |
|
|
|
} |
|
|
|
|
|
|
|
getMarkImageUrl(markName: string): string { |
|
|
|
|