From 87c49b8b24437b32ffaf9176c34e079c261f6205 Mon Sep 17 00:00:00 2001 From: emkartal1 Date: Fri, 27 Jan 2023 16:05:57 +0100 Subject: [PATCH] Add API solution --- .vs/LolProject/v17/.suo | Bin 0 -> 11264 bytes .vs/VSWorkspaceState.json | 6 + src/EntityFramework_LoL/.gitignore | 428 ++++++++++++++++++ src/EntityFramework_LoL/README.md | 168 +++++++ .../Sources/ApiLol/ApiLol.csproj | 13 + .../Controllers/WeatherForecastController.cs | 33 ++ .../Sources/ApiLol/Program.cs | 25 + .../ApiLol/Properties/launchSettings.json | 31 ++ .../Sources/ApiLol/WeatherForecast.cs | 13 + .../ApiLol/appsettings.Development.json | 8 + .../Sources/ApiLol/appsettings.json | 9 + .../Sources/LeagueOfLegends.sln | 57 +++ .../Sources/Model/Champion.cs | 151 ++++++ .../Sources/Model/IDataManager.cs | 53 +++ .../Sources/Model/LargeImage.cs | 28 ++ .../Sources/Model/Model.csproj | 18 + src/EntityFramework_LoL/Sources/Model/Rune.cs | 69 +++ .../Sources/Model/RunePage.Category.cs | 17 + .../Sources/Model/RunePage.cs | 95 ++++ .../Sources/Model/Skill.cs | 63 +++ src/EntityFramework_LoL/Sources/Model/Skin.cs | 83 ++++ .../Sources/Model/enums/ChampionClass.cs | 15 + .../Sources/Model/enums/RuneFamily.cs | 11 + .../Sources/Model/enums/SkillType.cs | 12 + .../Sources/Shared/IGenericDataManager.cs | 11 + .../Sources/Shared/Shared.csproj | 9 + .../Sources/StubLib/Extensions.cs | 65 +++ .../Sources/StubLib/StubData.Champions.cs | 100 ++++ .../Sources/StubLib/StubData.RunePages.cs | 83 ++++ .../Sources/StubLib/StubData.Runes.cs | 69 +++ .../Sources/StubLib/StubData.Skins.cs | 80 ++++ .../Sources/StubLib/StubData.cs | 35 ++ .../Sources/StubLib/StubLib.csproj | 12 + .../Tests/ConsoleTests/ConsoleTests.csproj | 20 + .../Sources/Tests/ConsoleTests/Program.cs | 338 ++++++++++++++ 35 files changed, 2228 insertions(+) create mode 100644 .vs/LolProject/v17/.suo create mode 100644 .vs/VSWorkspaceState.json create mode 100644 src/EntityFramework_LoL/.gitignore create mode 100644 src/EntityFramework_LoL/README.md create mode 100644 src/EntityFramework_LoL/Sources/ApiLol/ApiLol.csproj create mode 100644 src/EntityFramework_LoL/Sources/ApiLol/Controllers/WeatherForecastController.cs create mode 100644 src/EntityFramework_LoL/Sources/ApiLol/Program.cs create mode 100644 src/EntityFramework_LoL/Sources/ApiLol/Properties/launchSettings.json create mode 100644 src/EntityFramework_LoL/Sources/ApiLol/WeatherForecast.cs create mode 100644 src/EntityFramework_LoL/Sources/ApiLol/appsettings.Development.json create mode 100644 src/EntityFramework_LoL/Sources/ApiLol/appsettings.json create mode 100644 src/EntityFramework_LoL/Sources/LeagueOfLegends.sln create mode 100644 src/EntityFramework_LoL/Sources/Model/Champion.cs create mode 100644 src/EntityFramework_LoL/Sources/Model/IDataManager.cs create mode 100644 src/EntityFramework_LoL/Sources/Model/LargeImage.cs create mode 100644 src/EntityFramework_LoL/Sources/Model/Model.csproj create mode 100644 src/EntityFramework_LoL/Sources/Model/Rune.cs create mode 100644 src/EntityFramework_LoL/Sources/Model/RunePage.Category.cs create mode 100644 src/EntityFramework_LoL/Sources/Model/RunePage.cs create mode 100644 src/EntityFramework_LoL/Sources/Model/Skill.cs create mode 100644 src/EntityFramework_LoL/Sources/Model/Skin.cs create mode 100644 src/EntityFramework_LoL/Sources/Model/enums/ChampionClass.cs create mode 100644 src/EntityFramework_LoL/Sources/Model/enums/RuneFamily.cs create mode 100644 src/EntityFramework_LoL/Sources/Model/enums/SkillType.cs create mode 100644 src/EntityFramework_LoL/Sources/Shared/IGenericDataManager.cs create mode 100644 src/EntityFramework_LoL/Sources/Shared/Shared.csproj create mode 100644 src/EntityFramework_LoL/Sources/StubLib/Extensions.cs create mode 100644 src/EntityFramework_LoL/Sources/StubLib/StubData.Champions.cs create mode 100644 src/EntityFramework_LoL/Sources/StubLib/StubData.RunePages.cs create mode 100644 src/EntityFramework_LoL/Sources/StubLib/StubData.Runes.cs create mode 100644 src/EntityFramework_LoL/Sources/StubLib/StubData.Skins.cs create mode 100644 src/EntityFramework_LoL/Sources/StubLib/StubData.cs create mode 100644 src/EntityFramework_LoL/Sources/StubLib/StubLib.csproj create mode 100644 src/EntityFramework_LoL/Sources/Tests/ConsoleTests/ConsoleTests.csproj create mode 100644 src/EntityFramework_LoL/Sources/Tests/ConsoleTests/Program.cs diff --git a/.vs/LolProject/v17/.suo b/.vs/LolProject/v17/.suo new file mode 100644 index 0000000000000000000000000000000000000000..52cf1a557d8d01f20140b2c18a661ea33a24c6b4 GIT binary patch literal 11264 zcmeHNTW=dh6h2NV&~R(H1SoxoP=xw`gOjF-DWWP(Td0H^Q|D5lNXX7Qm&P}(Hw1V> z;+a3d3+hkcAMnC+c;yWwBz^><;rnKHyyNxmdcAH+LVc{w&d$uvH|NYbGv}PmuLtLT zfAG`!KO{g`<&-=;JR?sV^%~DL18oyDeXH zDHGF#obIgo={|3r{o#T0#q4jH=g{wGPqB(XY|4GP4fIWvZpv4EM(J*zkg*Ov#opZ- z{&XJIP+vtFpSUflVFtETag`v8GOnuEFX}cWV;OU~qxzZkFX3U=t5}jfpwwgs{PWr} zkZ+*IHeU=W6aOjHkKszn{{;GKyM7Vne@q5YrfhT-=lZPo{5OHUQ|mz-C-Bo%mn1)$j;HhnI7qHS4~e9ybVinoDJ ze^T!~!S=9c&X@iYX%XC)fkm_(An*6g!tEFJ7yeg=cgi5DpIJ{^(a$%4S%IXt@T1?k zrX;>0+jwg0PBHh%6!`S{=&O;gW4)X3M(e<}aZl>^x^IhIfczQvX&+G6$K78;<3+E- zvXcI;dI|2&t;Q&Rrv!(YZl z3hE#ECw>WWU>%yt-64+N8JhoY{VzZcb)Yg1HDwXTJLiS{XJGrIt}J^@1^K@YrYK!tx5C1 zCoXL&DL#EW#*8GBvjX_06}UUmG<1GX*<=$d@-c9mcy7rZ^q{u7D{>Y1^rsn9CdKD| zL7gQf#a{+Gb&!*uPV+R>=k9~g!+Wy8x|z9t+WvG&%EXFo|J!{SKO~jarkS>3uwp^G@h$LIRt4o z1^@JYbo^T{x1FlJ|6cX);`m?V-+vPvzu)ui@BTa}f1dvRe&dhYk5&S-1MbIZY1sFv zhr{60j`+SmM(Y|L6VtHsPYe{%(VurjhXmC+mNB~yQ)iBI)a8t^a%r%%ACu-?zC-!n z!?h?^WL;LUr}MOHqf9?^SDlUg5>S&F)X^(oRLs+HU7eHk64{&HLCy0c?xU44!#V-_ z(6H;zxYymwO-)`wEl2(&hd|r>Wjjw^DK2kAA0^nHHvhwMMs)lnFpB@5?D)TcU2H`r zd*Yo*BNKvcAd=F=|BM&8TRkc=t?E&YImkFC89$hR2+w~+OXDKqAM+b=bWgv9Yp)}j zAU^YPJY8EjKcll={#ekzfxo{qU##QrFnl)y%}ju$@`G{nVg7~rZ06Lc2mZ{WOFXlq z@csOo?`cGjBtrY+nM@xbDL!+xI{pmu@8c)V|0(%j7y#dl|AY9W{2y~3k1zihl>Z5| z|AF&A|1R?535kWar+WoynFLE?e1!>OwU?o2y*1DwkAH)E#l%JK%1d zo~C-fpta#mttt`DAdj3w+!#mQvx(~&- macOS +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# ---> VisualStudio +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml + diff --git a/src/EntityFramework_LoL/README.md b/src/EntityFramework_LoL/README.md new file mode 100644 index 0000000..3228583 --- /dev/null +++ b/src/EntityFramework_LoL/README.md @@ -0,0 +1,168 @@ +# prepaLoL + +## Diagramme de classes du modèle +```mermaid +classDiagram +class LargeImage{ + +/Base64 : string +} +class Champion{ + +/Name : string + +/Bio : string + +/Icon : string + +/Characteristics : Dictionary~string, int~ + ~ AddSkin(skin : Skin) bool + ~ RemoveSkin(skin: Skin) bool + + AddSkill(skill: Skill) bool + + RemoveSkill(skill: Skill) bool + + AddCharacteristics(someCharacteristics : params Tuple~string, int~[]) + + RemoveCharacteristics(label : string) bool + + this~label : string~ : int? +} +Champion --> "1" LargeImage : Image +class ChampionClass{ + <> + Unknown, + Assassin, + Fighter, + Mage, + Marksman, + Support, + Tank, +} +Champion --> "1" ChampionClass : Class +class Skin{ + +/Name : string + +/Description : string + +/Icon : string + +/Price : float +} +Skin --> "1" LargeImage : Image +Champion "1" -- "*" Skin +class Skill{ + +/Name : string + +/Description : string +} +class SkillType{ + <> + Unknown, + Basic, + Passive, + Ultimate, +} +Skill --> "1" SkillType : Type +Champion --> "*" Skill +class Rune{ + +/Name : string + +/Description : string +} +Rune --> "1" LargeImage : Image +class RuneFamily{ + <> + Unknown, + Precision, + Domination +} +Rune --> "1" RuneFamily : Family +class Category{ + <> + Major, + Minor1, + Minor2, + Minor3, + OtherMinor1, + OtherMinor2 +} +class RunePage{ + +/Name : string + +/this[category : Category] : Rune? + - CheckRunes(newRuneCategory : Category) + - CheckFamilies(cat1 : Category, cat2 : Category) bool? + - UpdateMajorFamily(minor : Category, expectedValue : bool) +} +RunePage --> "*" Rune : Dictionary~Category,Rune~ +``` + +## Diagramme de classes des interfaces de gestion de l'accès aux données +```mermaid +classDiagram +direction LR; +class IGenericDataManager~T~{ + <> + GetNbItems() Task~int~ + GetItems(index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~T~~ + GetNbItemsByName(substring : string) + GetItemsByName(substring : string, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~T~~ + UpdateItem(oldItem : T, newItem : T) Task~T~~ + AddItem(item : T) Task~T~ + DeleteItem(item : T) Task~bool~ +} +class IChampionsManager{ + <> + GetNbItemsByCharacteristic(charName : string) + GetItemsByCharacteristic(charName : string, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Champion?~~ + GetNbItemsByClass(championClass : ChampionClass) + GetItemsByClass(championClass : ChampionClass, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Champion?~~ + GetNbItemsBySkill(skill : Skill?) + GetItemsBySkill(skill : Skill?, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Champion?~~ + GetNbItemsBySkill(skill : string) + GetItemsBySkill(skill : string, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Champion?~~ + GetNbItemsByRunePage(runePage : RunePage?) + GetItemsByRunePage(runePage : RunePage?, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Champion?~~ +} +class ISkinsManager{ + <> + GetNbItemsByChampion(champion : Champion?) + GetItemsByChampion(champion : Champion?, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Skin?~~ +} +class IRunesManager{ + <> + GetNbItemsByFamily(family : RuneFamily) + GetItemsByFamily(family : RuneFamily, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Rune?~~ +} +class IRunePagesManager{ + <> + GetNbItemsByRune(rune : Rune?) + GetItemsByRune(rune : Rune?, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~RunePage?~~ + GetNbItemsByChampion(champion : Champion?) + GetItemsByChampion(champion : Champion?, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~RunePage?~~ +} + +IGenericDataManager~Champion?~ <|.. IChampionsManager : T--Champion? +IGenericDataManager~Skin?~ <|.. ISkinsManager : T--Skin? +IGenericDataManager~Rune?~ <|.. IRunesManager : T--Rune? +IGenericDataManager~RunePage?~ <|.. IRunePagesManager : T--RunePage? +class IDataManager{ + <> +} +IChampionsManager <-- IDataManager : ChampionsMgr +ISkinsManager <-- IDataManager : SkinsMgr +IRunesManager <-- IDataManager : RunesMgr +IRunePagesManager <-- IDataManager : RunePagesMgr +``` + +## Diagramme de classes simplifié du Stub +```mermaid +classDiagram +direction TB; + +IDataManager <|.. StubData + +ChampionsManager ..|> IChampionsManager +StubData --> ChampionsManager + +RunesManager ..|> IRunesManager +StubData --> RunesManager + +RunePagesManager ..|> IRunePagesManager +StubData --> RunePagesManager + +SkinsManager ..|> ISkinsManager +StubData --> SkinsManager + +StubData --> RunesManager +StubData --> "*" Champion +StubData --> "*" Rune +StubData --> "*" RunePages +StubData --> "*" Skins +``` \ No newline at end of file diff --git a/src/EntityFramework_LoL/Sources/ApiLol/ApiLol.csproj b/src/EntityFramework_LoL/Sources/ApiLol/ApiLol.csproj new file mode 100644 index 0000000..4289e82 --- /dev/null +++ b/src/EntityFramework_LoL/Sources/ApiLol/ApiLol.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/src/EntityFramework_LoL/Sources/ApiLol/Controllers/WeatherForecastController.cs b/src/EntityFramework_LoL/Sources/ApiLol/Controllers/WeatherForecastController.cs new file mode 100644 index 0000000..3c0f0e8 --- /dev/null +++ b/src/EntityFramework_LoL/Sources/ApiLol/Controllers/WeatherForecastController.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Mvc; + +namespace ApiLol.Controllers +{ + [ApiController] + [Route("[controller]")] + public class WeatherForecastController : ControllerBase + { + private static readonly string[] Summaries = new[] + { + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" + }; + + private readonly ILogger _logger; + + public WeatherForecastController(ILogger logger) + { + _logger = logger; + } + + [HttpGet(Name = "GetWeatherForecast")] + public IEnumerable Get() + { + return Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = DateTime.Now.AddDays(index), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = Summaries[Random.Shared.Next(Summaries.Length)] + }) + .ToArray(); + } + } +} \ No newline at end of file diff --git a/src/EntityFramework_LoL/Sources/ApiLol/Program.cs b/src/EntityFramework_LoL/Sources/ApiLol/Program.cs new file mode 100644 index 0000000..15eacee --- /dev/null +++ b/src/EntityFramework_LoL/Sources/ApiLol/Program.cs @@ -0,0 +1,25 @@ +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. + +builder.Services.AddControllers(); +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseHttpsRedirection(); + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); diff --git a/src/EntityFramework_LoL/Sources/ApiLol/Properties/launchSettings.json b/src/EntityFramework_LoL/Sources/ApiLol/Properties/launchSettings.json new file mode 100644 index 0000000..fd7dcb3 --- /dev/null +++ b/src/EntityFramework_LoL/Sources/ApiLol/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:55275", + "sslPort": 44383 + } + }, + "profiles": { + "ApiLol": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7252;http://localhost:5252", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/src/EntityFramework_LoL/Sources/ApiLol/WeatherForecast.cs b/src/EntityFramework_LoL/Sources/ApiLol/WeatherForecast.cs new file mode 100644 index 0000000..88bf90d --- /dev/null +++ b/src/EntityFramework_LoL/Sources/ApiLol/WeatherForecast.cs @@ -0,0 +1,13 @@ +namespace ApiLol +{ + public class WeatherForecast + { + public DateTime Date { get; set; } + + public int TemperatureC { get; set; } + + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + + public string? Summary { get; set; } + } +} \ No newline at end of file diff --git a/src/EntityFramework_LoL/Sources/ApiLol/appsettings.Development.json b/src/EntityFramework_LoL/Sources/ApiLol/appsettings.Development.json new file mode 100644 index 0000000..ff66ba6 --- /dev/null +++ b/src/EntityFramework_LoL/Sources/ApiLol/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/src/EntityFramework_LoL/Sources/ApiLol/appsettings.json b/src/EntityFramework_LoL/Sources/ApiLol/appsettings.json new file mode 100644 index 0000000..4d56694 --- /dev/null +++ b/src/EntityFramework_LoL/Sources/ApiLol/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/src/EntityFramework_LoL/Sources/LeagueOfLegends.sln b/src/EntityFramework_LoL/Sources/LeagueOfLegends.sln new file mode 100644 index 0000000..d877689 --- /dev/null +++ b/src/EntityFramework_LoL/Sources/LeagueOfLegends.sln @@ -0,0 +1,57 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32616.157 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Model", "Model\Model.csproj", "{2960F9BA-49DE-494D-92E3-CE5A794BA1A9}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{C76D0C23-1FFA-4963-93CD-E12BD643F030}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleTests", "Tests\ConsoleTests\ConsoleTests.csproj", "{1889FA6E-B7C6-416E-8628-9449FB9070B9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shared", "Shared\Shared.csproj", "{3B720C0C-53FE-4642-A2DB-87FD8634CD74}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Stub", "Stub", "{2C607793-B163-4731-A4D1-AFE8A7C4C170}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StubLib", "StubLib\StubLib.csproj", "{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ApiLol", "ApiLol\ApiLol.csproj", "{D59C9C7B-9BC2-4601-959D-BFA97E46D017}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2960F9BA-49DE-494D-92E3-CE5A794BA1A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2960F9BA-49DE-494D-92E3-CE5A794BA1A9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2960F9BA-49DE-494D-92E3-CE5A794BA1A9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2960F9BA-49DE-494D-92E3-CE5A794BA1A9}.Release|Any CPU.Build.0 = Release|Any CPU + {1889FA6E-B7C6-416E-8628-9449FB9070B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1889FA6E-B7C6-416E-8628-9449FB9070B9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1889FA6E-B7C6-416E-8628-9449FB9070B9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1889FA6E-B7C6-416E-8628-9449FB9070B9}.Release|Any CPU.Build.0 = Release|Any CPU + {3B720C0C-53FE-4642-A2DB-87FD8634CD74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3B720C0C-53FE-4642-A2DB-87FD8634CD74}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B720C0C-53FE-4642-A2DB-87FD8634CD74}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3B720C0C-53FE-4642-A2DB-87FD8634CD74}.Release|Any CPU.Build.0 = Release|Any CPU + {B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}.Release|Any CPU.Build.0 = Release|Any CPU + {D59C9C7B-9BC2-4601-959D-BFA97E46D017}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D59C9C7B-9BC2-4601-959D-BFA97E46D017}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D59C9C7B-9BC2-4601-959D-BFA97E46D017}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D59C9C7B-9BC2-4601-959D-BFA97E46D017}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {1889FA6E-B7C6-416E-8628-9449FB9070B9} = {C76D0C23-1FFA-4963-93CD-E12BD643F030} + {B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB} = {2C607793-B163-4731-A4D1-AFE8A7C4C170} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {92F3083D-793F-4552-8A9A-0AD6534159C9} + EndGlobalSection +EndGlobal diff --git a/src/EntityFramework_LoL/Sources/Model/Champion.cs b/src/EntityFramework_LoL/Sources/Model/Champion.cs new file mode 100644 index 0000000..3a50658 --- /dev/null +++ b/src/EntityFramework_LoL/Sources/Model/Champion.cs @@ -0,0 +1,151 @@ +using System.Collections.Immutable; +using System.Collections.ObjectModel; +using System.Numerics; +using System.Text; + +namespace Model; +public class Champion : IEquatable +{ + public string Name + { + get => name; + private init + { + if(string.IsNullOrWhiteSpace(value)) + { + name = "Unknown"; + return; + } + name = value; + } + } + private readonly string name = null!; + + public string Bio + { + get => bio; + set + { + if(value == null) + { + bio = ""; + return; + } + bio = value; + } + } + private string bio = ""; + + public ChampionClass Class { get; set; } + + public string Icon { get; set; } + + public LargeImage Image { get; set; } + + public Champion(string name, ChampionClass champClass = ChampionClass.Unknown, string icon = "", string image = "", string bio = "") + { + Name = name; + Class = champClass; + Icon = icon; + Image = new LargeImage(image); + Bio = bio; + Characteristics = new ReadOnlyDictionary(characteristics); + Skins = new ReadOnlyCollection(skins); + } + + public ReadOnlyCollection Skins { get; private set; } + private List skins = new (); + + public ReadOnlyDictionary Characteristics { get; private set; } + private readonly Dictionary characteristics = new Dictionary(); + + public ImmutableHashSet Skills => skills.ToImmutableHashSet(); + private HashSet skills = new HashSet(); + + internal bool AddSkin(Skin skin) + { + if (skins.Contains(skin)) + return false; + skins.Add(skin); + return true; + } + + internal bool RemoveSkin(Skin skin) + => skins.Remove(skin); + + public bool AddSkill(Skill skill) + => skills.Add(skill); + + public bool RemoveSkill(Skill skill) + => skills.Remove(skill); + + public void AddCharacteristics(params Tuple[] someCharacteristics) + { + foreach(var c in someCharacteristics) + { + characteristics[c.Item1] = c.Item2; + } + } + + public bool RemoveCharacteristics(string label) + => characteristics.Remove(label); + + public int? this[string label] + { + get + { + if(!characteristics.TryGetValue(label, out int value)) return null; + else return value; + } + set + { + if(!value.HasValue) + { + RemoveCharacteristics(label); + return; + } + characteristics[label] = value.Value; + } + } + + public override bool Equals(object? obj) + { + if(ReferenceEquals(obj, null)) return false; + if(ReferenceEquals(obj, this)) return true; + if(GetType() != obj.GetType()) return false; + return Equals(obj as Champion); + } + + public override int GetHashCode() + => Name.GetHashCode() % 997; + + public bool Equals(Champion? other) + => Name.Equals(other?.Name); + + public override string ToString() + { + StringBuilder sb = new StringBuilder($"{Name} ({Class})"); + if(!string.IsNullOrWhiteSpace(bio)) + { + sb.AppendLine($"\t{bio}"); + } + if(characteristics.Any()) + { + sb.AppendLine("\tCharacteristics:"); + foreach(var characteristic in characteristics) + { + sb.AppendLine($"\t\t{characteristic.Key} - {characteristic.Value}"); + } + } + if(skills.Any()) + { + sb.AppendLine("\tSkills:"); + foreach(var skill in Skills) + { + sb.AppendLine($"\t\t{skill.Name} - {skill.Description}"); + } + } + return sb.ToString(); + } +} + diff --git a/src/EntityFramework_LoL/Sources/Model/IDataManager.cs b/src/EntityFramework_LoL/Sources/Model/IDataManager.cs new file mode 100644 index 0000000..a185e15 --- /dev/null +++ b/src/EntityFramework_LoL/Sources/Model/IDataManager.cs @@ -0,0 +1,53 @@ +using System; +using Shared; + +namespace Model +{ + public interface IDataManager + { + IChampionsManager ChampionsMgr { get; } + ISkinsManager SkinsMgr { get; } + IRunesManager RunesMgr { get; } + IRunePagesManager RunePagesMgr { get; } + } + + public interface IChampionsManager : IGenericDataManager + { + Task GetNbItemsByCharacteristic(string charName); + Task> GetItemsByCharacteristic(string charName, int index, int count, string? orderingPropertyName = null, bool descending = false); + + Task GetNbItemsByClass(ChampionClass championClass); + Task> GetItemsByClass(ChampionClass championClass, int index, int count, string? orderingPropertyName = null, bool descending = false); + + Task GetNbItemsBySkill(Skill? skill); + Task> GetItemsBySkill(Skill? skill, int index, int count, string? orderingPropertyName = null, bool descending = false); + + Task GetNbItemsByRunePage(RunePage? runePage); + Task> GetItemsByRunePage(RunePage? runePage, int index, int count, string? orderingPropertyName = null, bool descending = false); + + Task GetNbItemsBySkill(string skill); + Task> GetItemsBySkill(string skill, int index, int count, string? orderingPropertyName = null, bool descending = false); + } + + public interface ISkinsManager : IGenericDataManager + { + Task GetNbItemsByChampion(Champion? champion); + Task> GetItemsByChampion(Champion? champion, int index, int count, string? orderingPropertyName = null, bool descending = false); + } + + public interface IRunesManager : IGenericDataManager + { + Task GetNbItemsByFamily(RuneFamily family); + Task> GetItemsByFamily(RuneFamily family, int index, int count, string? orderingPropertyName = null, bool descending = false); + } + + public interface IRunePagesManager : IGenericDataManager + { + Task GetNbItemsByRune(Rune? rune); + Task> GetItemsByRune(Rune? rune, int index, int count, string? orderingPropertyName = null, bool descending = false); + + Task GetNbItemsByChampion(Champion? champion); + Task> GetItemsByChampion(Champion? champion, int index, int count, string? orderingPropertyName = null, bool descending = false); + } +} + diff --git a/src/EntityFramework_LoL/Sources/Model/LargeImage.cs b/src/EntityFramework_LoL/Sources/Model/LargeImage.cs new file mode 100644 index 0000000..56d6696 --- /dev/null +++ b/src/EntityFramework_LoL/Sources/Model/LargeImage.cs @@ -0,0 +1,28 @@ +using System; +namespace Model +{ + public class LargeImage : IEquatable + { + public string Base64 { get; set; } + + public LargeImage(string base64) + { + Base64 = base64; + } + + public bool Equals(LargeImage? other) + => other != null && other.Base64.Equals(Base64); + + public override bool Equals(object? obj) + { + if(ReferenceEquals(obj, null)) return false; + if(ReferenceEquals(obj!, this)) return true; + if(GetType() != obj!.GetType()) return false; + return Equals(obj! as LargeImage); + } + + public override int GetHashCode() + => Base64.Substring(0, 10).GetHashCode(); + } +} + diff --git a/src/EntityFramework_LoL/Sources/Model/Model.csproj b/src/EntityFramework_LoL/Sources/Model/Model.csproj new file mode 100644 index 0000000..27b2839 --- /dev/null +++ b/src/EntityFramework_LoL/Sources/Model/Model.csproj @@ -0,0 +1,18 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + diff --git a/src/EntityFramework_LoL/Sources/Model/Rune.cs b/src/EntityFramework_LoL/Sources/Model/Rune.cs new file mode 100644 index 0000000..7b5047b --- /dev/null +++ b/src/EntityFramework_LoL/Sources/Model/Rune.cs @@ -0,0 +1,69 @@ +using System; + +namespace Model +{ + public class Rune : IEquatable + { + public string Name + { + get => name; + private init + { + if(string.IsNullOrWhiteSpace(value)) + { + throw new ArgumentException("a Rune must have a name"); + } + name = value; + } + } + private readonly string name = null!; + + public string Description + { + get => description; + set + { + if(string.IsNullOrWhiteSpace(value)) + { + description = ""; + return; + } + description = value; + } + } + private string description = ""; + + public RuneFamily Family { get; set; } + + public string Icon { get; set; } + + public LargeImage Image { get; set; } + + public Rune(string name, RuneFamily family, string icon = "", string image = "", string description = "") + { + Name = name; + Family = family; + Icon = icon; + Image = new LargeImage(image); + Description = description; + } + + public override bool Equals(object? obj) + { + if(ReferenceEquals(obj, null)) return false; + if(ReferenceEquals(obj, this)) return true; + if(GetType() != obj.GetType()) return false; + return Equals(obj as Rune); + } + + public bool Equals(Rune? other) + => Name.Equals(other?.Name); + + public override int GetHashCode() + => Name.GetHashCode() % 281; + + public override string ToString() + => $"{Name} ({Family})"; + } +} + diff --git a/src/EntityFramework_LoL/Sources/Model/RunePage.Category.cs b/src/EntityFramework_LoL/Sources/Model/RunePage.Category.cs new file mode 100644 index 0000000..1047c0e --- /dev/null +++ b/src/EntityFramework_LoL/Sources/Model/RunePage.Category.cs @@ -0,0 +1,17 @@ +using System; +namespace Model +{ + public partial class RunePage + { + public enum Category + { + Major, + Minor1, + Minor2, + Minor3, + OtherMinor1, + OtherMinor2 + } + } +} + diff --git a/src/EntityFramework_LoL/Sources/Model/RunePage.cs b/src/EntityFramework_LoL/Sources/Model/RunePage.cs new file mode 100644 index 0000000..cf56628 --- /dev/null +++ b/src/EntityFramework_LoL/Sources/Model/RunePage.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.ObjectModel; + +namespace Model +{ + public partial class RunePage + { + public string Name + { + get => name; + private init + { + if(string.IsNullOrWhiteSpace(value)) + { + throw new ArgumentException("a Rune Page must have a name"); + } + name = value; + } + } + private readonly string name = null!; + + public ReadOnlyDictionary Runes { get; private set; } + private Dictionary runes = new Dictionary(); + + public RunePage(string name) + { + Name = name; + Runes = new ReadOnlyDictionary(runes); + } + + public Rune? this[Category category] + { + get + { + if(runes.TryGetValue(category, out Rune? rune)) + { + return rune; + } + return null; + } + set + { + if(value == null) + { + runes.Remove(category); + } + runes[category] = value!; + CheckRunes(category); + } + } + + private void CheckRunes(Category newRuneCategory) + { + switch(newRuneCategory) + { + case Category.Major: + UpdateMajorFamily(Category.Minor1, true); + UpdateMajorFamily(Category.Minor2, true); + UpdateMajorFamily(Category.Minor3, true); + UpdateMajorFamily(Category.OtherMinor1, false); + UpdateMajorFamily(Category.OtherMinor2, false); + break; + case Category.Minor1: + case Category.Minor2: + case Category.Minor3: + UpdateMajorFamily(newRuneCategory, true); + break; + case Category.OtherMinor1: + case Category.OtherMinor2: + UpdateMajorFamily(newRuneCategory, false); + break; + } + } + + private bool? CheckFamilies(Category cat1, Category cat2) + { + runes.TryGetValue(cat1, out Rune? rune1); + runes.TryGetValue(cat2, out Rune? rune2); + if(rune1 == null || rune2 == null) + { + return null; + } + return rune1.Family == rune2.Family; + } + + private void UpdateMajorFamily(Category minor, bool expectedValue) + { + if(CheckFamilies(Category.Major, minor).GetValueOrDefault(expectedValue) == expectedValue) + { + runes.Remove(minor); + } + } + } +} + diff --git a/src/EntityFramework_LoL/Sources/Model/Skill.cs b/src/EntityFramework_LoL/Sources/Model/Skill.cs new file mode 100644 index 0000000..0679ea6 --- /dev/null +++ b/src/EntityFramework_LoL/Sources/Model/Skill.cs @@ -0,0 +1,63 @@ +using System; + +namespace Model +{ + public class Skill : IEquatable + { + public SkillType Type { get; private set; } + + public string Name + { + get => name; + private init + { + if (string.IsNullOrWhiteSpace(value)) + { + throw new ArgumentException("a Skill needs a name"); + } + name = value; + } + } + private readonly string name = null!; + + public string Description + { + get => description; + set + { + if(string.IsNullOrWhiteSpace(value)) + { + description = ""; + return; + } + description = value; + } + } + private string description = ""; + + public Skill(string name, SkillType type, string description = "") + { + Name = name; + Type = type; + Description = description ?? ""; + } + + public override bool Equals(object? obj) + { + if(ReferenceEquals(obj, null)) return false; + if(ReferenceEquals(obj, this)) return true; + if(GetType() != obj.GetType()) return false; + return Equals(obj as Skill); + } + + public bool Equals(Skill? other) + => Name.Equals(other?.Name) && Type == other.Type; + + public override int GetHashCode() + => Name.GetHashCode() % 281; + + public override string ToString() + => $"{Name} ({Type})"; + } +} + diff --git a/src/EntityFramework_LoL/Sources/Model/Skin.cs b/src/EntityFramework_LoL/Sources/Model/Skin.cs new file mode 100644 index 0000000..2d8fb78 --- /dev/null +++ b/src/EntityFramework_LoL/Sources/Model/Skin.cs @@ -0,0 +1,83 @@ +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Model +{ + public class Skin : IEquatable + { + public string Name + { + get => name; + private init + { + if(string.IsNullOrWhiteSpace(value)) + { + throw new ArgumentException("A skin must have a name"); + } + name = value; + } + } + private readonly string name = null!; + + public string Description + { + get => description; + set + { + if (string.IsNullOrWhiteSpace(value)) + { + description = ""; + return; + } + description = value; + } + } + private string description = ""; + + public string Icon { get; set; } + public LargeImage Image { get; set; } + + public float Price { get; set; } + + public Champion Champion + { + get => champion; + private init + { + if (value == null) + throw new ArgumentNullException("A skill can't have a null champion"); + champion = value; + } + } + private readonly Champion champion = null!; + + public Skin(string name, Champion champion, float price = 0.0f, string icon = "", string image = "", string description = "") + { + Name = name; + Champion = champion; + Champion.AddSkin(this); + Price = price; + Icon = icon; + Image = new LargeImage(image); + Description = description; + } + + public override bool Equals(object? obj) + { + if(ReferenceEquals(obj, null)) return false; + if(ReferenceEquals(obj, this)) return true; + if(GetType() != obj.GetType()) return false; + return Equals(obj as Skin); + } + + public bool Equals(Skin? other) + => Name.Equals(other?.Name); + + public override int GetHashCode() + => Name.GetHashCode() % 997; + + public override string ToString() + => $"{Name}"; + } +} + diff --git a/src/EntityFramework_LoL/Sources/Model/enums/ChampionClass.cs b/src/EntityFramework_LoL/Sources/Model/enums/ChampionClass.cs new file mode 100644 index 0000000..d169512 --- /dev/null +++ b/src/EntityFramework_LoL/Sources/Model/enums/ChampionClass.cs @@ -0,0 +1,15 @@ +using System; +namespace Model +{ + public enum ChampionClass + { + Unknown, + Assassin, + Fighter, + Mage, + Marksman, + Support, + Tank, + } +} + diff --git a/src/EntityFramework_LoL/Sources/Model/enums/RuneFamily.cs b/src/EntityFramework_LoL/Sources/Model/enums/RuneFamily.cs new file mode 100644 index 0000000..07a232c --- /dev/null +++ b/src/EntityFramework_LoL/Sources/Model/enums/RuneFamily.cs @@ -0,0 +1,11 @@ +using System; +namespace Model +{ + public enum RuneFamily + { + Unknown, + Precision, + Domination + } +} + diff --git a/src/EntityFramework_LoL/Sources/Model/enums/SkillType.cs b/src/EntityFramework_LoL/Sources/Model/enums/SkillType.cs new file mode 100644 index 0000000..d7fc8da --- /dev/null +++ b/src/EntityFramework_LoL/Sources/Model/enums/SkillType.cs @@ -0,0 +1,12 @@ +using System; +namespace Model +{ + public enum SkillType + { + Unknown, + Basic, + Passive, + Ultimate + } +} + diff --git a/src/EntityFramework_LoL/Sources/Shared/IGenericDataManager.cs b/src/EntityFramework_LoL/Sources/Shared/IGenericDataManager.cs new file mode 100644 index 0000000..ed3ac48 --- /dev/null +++ b/src/EntityFramework_LoL/Sources/Shared/IGenericDataManager.cs @@ -0,0 +1,11 @@ +namespace Shared; +public interface IGenericDataManager +{ + Task GetNbItems(); + Task> GetItems(int index, int count, string? orderingPropertyName = null, bool descending = false); + Task GetNbItemsByName(string substring); + Task> GetItemsByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false); + Task UpdateItem(T oldItem, T newItem); + Task AddItem(T item); + Task DeleteItem(T item); +} diff --git a/src/EntityFramework_LoL/Sources/Shared/Shared.csproj b/src/EntityFramework_LoL/Sources/Shared/Shared.csproj new file mode 100644 index 0000000..bafd05b --- /dev/null +++ b/src/EntityFramework_LoL/Sources/Shared/Shared.csproj @@ -0,0 +1,9 @@ + + + + net6.0 + enable + enable + + + diff --git a/src/EntityFramework_LoL/Sources/StubLib/Extensions.cs b/src/EntityFramework_LoL/Sources/StubLib/Extensions.cs new file mode 100644 index 0000000..ef2e82b --- /dev/null +++ b/src/EntityFramework_LoL/Sources/StubLib/Extensions.cs @@ -0,0 +1,65 @@ +using System; +using Model; + +namespace StubLib +{ + static class Extensions + { + internal static Task> GetItemsWithFilterAndOrdering(this IEnumerable collection, + Func filter, int index, int count, string? orderingPropertyName = null, bool descending = false) + { + IEnumerable temp = collection; + temp = temp.Where(item => filter(item)); + if(orderingPropertyName != null) + { + var prop = typeof(T).GetProperty(orderingPropertyName!); + if (prop != null) + { + temp = descending ? temp.OrderByDescending(item => prop.GetValue(item)) + : temp.OrderBy(item => prop.GetValue(item)); + } + } + return Task.FromResult>(temp.Skip(index*count).Take(count)); + } + + internal static Task GetNbItemsWithFilter(this IEnumerable collection, Func filter) + { + return Task.FromResult(collection.Count(item => filter(item))); + } + + internal static Task AddItem(this IList collection, T? item) + { + if(item == null || collection.Contains(item)) + { + return Task.FromResult(default(T)); + } + collection.Add(item); + return Task.FromResult(item); + } + + internal static Task DeleteItem(this IList collection, T? item) + { + if(item == null) + { + return Task.FromResult(false); + } + bool result = collection.Remove(item!); + return Task.FromResult(result); + } + + internal static Task UpdateItem(this IList collection, T? oldItem, T? newItem) + { + if(oldItem == null || newItem == null) return Task.FromResult(default(T)); + + if(!collection.Contains(oldItem)) + { + return Task.FromResult(default(T)); + } + + collection.Remove(oldItem!); + collection.Add(newItem!); + return Task.FromResult(newItem); + } + } +} + diff --git a/src/EntityFramework_LoL/Sources/StubLib/StubData.Champions.cs b/src/EntityFramework_LoL/Sources/StubLib/StubData.Champions.cs new file mode 100644 index 0000000..ad19275 --- /dev/null +++ b/src/EntityFramework_LoL/Sources/StubLib/StubData.Champions.cs @@ -0,0 +1,100 @@ +using System; +using Model; + +namespace StubLib +{ + public partial class StubData + { + private List champions = new() + { + new Champion("Akali", ChampionClass.Assassin), + new Champion("Aatrox", ChampionClass.Fighter), + new Champion("Ahri", ChampionClass.Mage), + new Champion("Akshan", ChampionClass.Marksman), + new Champion("Bard", ChampionClass.Support), + new Champion("Alistar", ChampionClass.Tank), + }; + + public class ChampionsManager : IChampionsManager + { + private readonly StubData parent; + + public ChampionsManager(StubData parent) + => this.parent = parent; + + public Task AddItem(Champion? item) + => parent.champions.AddItem(item); + + public Task DeleteItem(Champion? item) + => parent.champions.DeleteItem(item); + + public Task GetNbItems() + => Task.FromResult(parent.champions.Count); + + public Task> GetItems(int index, int count, string? orderingPropertyName = null, bool descending = false) + => parent.champions.GetItemsWithFilterAndOrdering( + c => true, + index, count, + orderingPropertyName, descending); + + private Func filterByCharacteristic = (champ, charName) => champ.Characteristics.Keys.Any(k => k.Contains(charName, StringComparison.InvariantCultureIgnoreCase)); + + public Task GetNbItemsByCharacteristic(string charName) + => parent.champions.GetNbItemsWithFilter(champ => filterByCharacteristic(champ, charName)); + + public Task> GetItemsByCharacteristic(string charName, int index, int count, string? orderingPropertyName = null, bool descending = false) + => parent.champions.GetItemsWithFilterAndOrdering( + champ => filterByCharacteristic(champ, charName), + index, count, orderingPropertyName, descending); + + private Func filterByClass = (champ, championClass) => champ.Class == championClass; + + public Task GetNbItemsByClass(ChampionClass championClass) + => parent.champions.GetNbItemsWithFilter( + champ => filterByClass(champ, championClass)); + + public Task> GetItemsByClass(ChampionClass championClass, int index, int count, string? orderingPropertyName, bool descending = false) + => parent.champions.GetItemsWithFilterAndOrdering( + champ => filterByClass(champ, championClass), + index, count, orderingPropertyName, descending); + + private Func filterBySkill = (champ, skill) => skill != null && champ.Skills.Contains(skill!); + + public Task GetNbItemsBySkill(Skill? skill) + => parent.champions.GetNbItemsWithFilter(champ => filterBySkill(champ, skill)); + + public Task> GetItemsBySkill(Skill? skill, int index, int count, string? orderingPropertyName = null, bool descending = false) + => parent.champions.GetItemsWithFilterAndOrdering(champ => filterBySkill(champ, skill), index, count, orderingPropertyName, descending); + + private static Func filterBySkillSubstring = (champ, skill) => champ.Skills.Any(s => s.Name.Contains(skill, StringComparison.InvariantCultureIgnoreCase)); + + public Task GetNbItemsBySkill(string skillSubstring) + => parent.champions.GetNbItemsWithFilter(champ => filterBySkillSubstring(champ, skillSubstring)); + + public Task> GetItemsBySkill(string skillSubstring, int index, int count, string? orderingPropertyName = null, bool descending = false) + => parent.champions.GetItemsWithFilterAndOrdering(champ => filterBySkillSubstring(champ, skillSubstring), index, count, orderingPropertyName, descending); + + public Task GetNbItemsByRunePage(RunePage? runePage) + => Task.FromResult(parent.championsAndRunePages.Count(tuple => tuple.Item2.Equals(runePage))); + + public Task> GetItemsByRunePage(RunePage? runePage, int index, int count, string? orderingPropertyName = null, bool descending = false) + => Task.FromResult> + (parent.championsAndRunePages + .Where(tuple => tuple.Item2.Equals(runePage)) + .Select(tuple => tuple.Item1) + .Skip(index*count).Take(count)); + + private Func filterByName = (champ, substring) => champ.Name.Contains(substring, StringComparison.InvariantCultureIgnoreCase); + + public Task GetNbItemsByName(string substring) + => parent.champions.GetNbItemsWithFilter(champ => filterByName(champ, substring)); + + public Task> GetItemsByName(string substring, int index, int count, string? orderingPropertyName, bool descending = false) + => parent.champions.GetItemsWithFilterAndOrdering(champ => filterByName(champ, substring), index, count, orderingPropertyName, descending); + + public Task UpdateItem(Champion? oldItem, Champion? newItem) + => parent.champions.UpdateItem(oldItem, newItem); + } + } +} + diff --git a/src/EntityFramework_LoL/Sources/StubLib/StubData.RunePages.cs b/src/EntityFramework_LoL/Sources/StubLib/StubData.RunePages.cs new file mode 100644 index 0000000..a08a947 --- /dev/null +++ b/src/EntityFramework_LoL/Sources/StubLib/StubData.RunePages.cs @@ -0,0 +1,83 @@ +using System; +using Model; + +namespace StubLib +{ + public partial class StubData + { + private readonly List runePages = new(); + + private void InitRunePages() + { + var runePage1 = new RunePage("rune page 1"); + runePage1[RunePage.Category.Major] = runes[0]; + runePage1[RunePage.Category.Minor1] = runes[1]; + runePage1[RunePage.Category.Minor2] = runes[2]; + runePage1[RunePage.Category.Minor3] = runes[3]; + runePage1[RunePage.Category.OtherMinor1] = runes[4]; + runePage1[RunePage.Category.OtherMinor2] = runes[5]; + runePages.Add(runePage1); + } + + public class RunePagesManager : IRunePagesManager + { + private readonly StubData parent; + + public RunePagesManager(StubData parent) + => this.parent = parent; + + private static Func filterByName + = (rp, substring) => rp.Name.Contains(substring, StringComparison.InvariantCultureIgnoreCase); + + private static Func filterByRune + = (rp, rune) => rune != null && rp.Runes.Values.Contains(rune!); + + public Task AddItem(RunePage? item) + => parent.runePages.AddItem(item); + + public Task DeleteItem(RunePage? item) + => parent.runePages.DeleteItem(item); + + public Task> GetItems(int index, int count, string? orderingPropertyName = null, bool descending = false) + => parent.runePages.GetItemsWithFilterAndOrdering( + rp => true, + index, count, orderingPropertyName, descending); + + public Task> GetItemsByChampion(Champion? champion, int index, int count, string? orderingPropertyName = null, bool descending = false) + => Task.FromResult>( + parent.championsAndRunePages + .Where(tuple => tuple.Item1.Equals(champion)) + .Select(tuple => tuple.Item2) + .Skip(index*count).Take(count)); + + public Task> GetItemsByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false) + => parent.runePages.GetItemsWithFilterAndOrdering( + rp => filterByName(rp, substring), + index, count, orderingPropertyName, descending); + + public Task> GetItemsByRune(Rune? rune, int index, int count, string? orderingPropertyName = null, bool descending = false) + => parent.runePages.GetItemsWithFilterAndOrdering( + rp => filterByRune(rp, rune), + index, count, orderingPropertyName, descending); + + public Task GetNbItems() + => parent.runePages.GetNbItemsWithFilter( + rp => true); + + public Task GetNbItemsByChampion(Champion? champion) + => Task.FromResult(parent.championsAndRunePages.Count(tuple => tuple.Item1.Equals(champion))); + + public Task GetNbItemsByName(string substring) + => parent.runePages.GetNbItemsWithFilter( + rp => filterByName(rp, substring)); + + public Task GetNbItemsByRune(Rune? rune) + => parent.runePages.GetNbItemsWithFilter( + rp => filterByRune(rp, rune)); + + public Task UpdateItem(RunePage? oldItem, RunePage? newItem) + => parent.runePages.UpdateItem(oldItem, newItem); + } + } +} + diff --git a/src/EntityFramework_LoL/Sources/StubLib/StubData.Runes.cs b/src/EntityFramework_LoL/Sources/StubLib/StubData.Runes.cs new file mode 100644 index 0000000..f0e8802 --- /dev/null +++ b/src/EntityFramework_LoL/Sources/StubLib/StubData.Runes.cs @@ -0,0 +1,69 @@ +using System; +using Model; + +namespace StubLib +{ + public partial class StubData + { + private readonly List runes = new() + { + new Rune("Conqueror", RuneFamily.Precision), + new Rune("Triumph", RuneFamily.Precision), + new Rune("Legend: Alacrity", RuneFamily.Precision), + new Rune("Legend: Tenacity", RuneFamily.Precision), + new Rune("last stand", RuneFamily.Domination), + new Rune("last stand 2", RuneFamily.Domination), + }; + + public class RunesManager : IRunesManager + { + private readonly StubData parent; + + public RunesManager(StubData parent) + => this.parent = parent; + + public Task AddItem(Rune? item) + => parent.runes.AddItem(item); + + public Task DeleteItem(Rune? item) + => parent.runes.DeleteItem(item); + + public Task> GetItems(int index, int count, string? orderingPropertyName = null, bool descending = false) + => parent.runes.GetItemsWithFilterAndOrdering( + r => true, + index, count, orderingPropertyName, descending); + + private static Func filterByRuneFamily + = (rune, family) => rune.Family == family; + + private static Func filterByName + = (rune, substring) => rune.Name.Contains(substring, StringComparison.InvariantCultureIgnoreCase); + + public Task> GetItemsByFamily(RuneFamily family, int index, int count, string? orderingPropertyName = null, bool descending = false) + => parent.runes.GetItemsWithFilterAndOrdering( + rune => filterByRuneFamily(rune, family), + index, count, orderingPropertyName, descending); + + public Task> GetItemsByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false) + => parent.runes.GetItemsWithFilterAndOrdering( + rune => filterByName(rune, substring), + index, count, orderingPropertyName, descending); + + public Task GetNbItems() + => parent.runes.GetNbItemsWithFilter( + rune => true); + + public Task GetNbItemsByFamily(RuneFamily family) + => parent.runes.GetNbItemsWithFilter( + rune => filterByRuneFamily(rune, family)); + + public Task GetNbItemsByName(string substring) + => parent.runes.GetNbItemsWithFilter( + rune => filterByName(rune, substring)); + + public Task UpdateItem(Rune? oldItem, Rune? newItem) + => parent.runes.UpdateItem(oldItem, newItem); + } + } +} + diff --git a/src/EntityFramework_LoL/Sources/StubLib/StubData.Skins.cs b/src/EntityFramework_LoL/Sources/StubLib/StubData.Skins.cs new file mode 100644 index 0000000..ff5fc08 --- /dev/null +++ b/src/EntityFramework_LoL/Sources/StubLib/StubData.Skins.cs @@ -0,0 +1,80 @@ +using System; +using Model; + +namespace StubLib +{ + public partial class StubData + { + private readonly List skins = new(); + + private void InitSkins() + { + skins.Add(new Skin("Stinger", champions[0])); + skins.Add(new Skin("Infernal", champions[0])); + skins.Add(new Skin("All-Star", champions[0])); + skins.Add(new Skin("Justicar", champions[1])); + skins.Add(new Skin("Mecha", champions[1])); + skins.Add(new Skin("Sea Hunter", champions[1])); + skins.Add(new Skin("Dynasty", champions[2])); + skins.Add(new Skin("Midnight", champions[2])); + skins.Add(new Skin("Foxfire", champions[2])); + skins.Add(new Skin("Cyber Pop", champions[3])); + skins.Add(new Skin("Crystal Rose", champions[3])); + skins.Add(new Skin("Elderwood", champions[4])); + skins.Add(new Skin("Snow Day", champions[4])); + skins.Add(new Skin("Bard", champions[4])); + skins.Add(new Skin("Black", champions[5])); + skins.Add(new Skin("Golden", champions[5])); + skins.Add(new Skin("Matador", champions[5])); + } + + public class SkinsManager : ISkinsManager + { + private readonly StubData parent; + + public SkinsManager(StubData parent) + => this.parent = parent; + + public Task AddItem(Skin? item) + => parent.skins.AddItem(item); + + public Task DeleteItem(Skin? item) + => parent.skins.DeleteItem(item); + + public Task> GetItems(int index, int count, string? orderingPropertyName = null, bool descending = false) + => parent.skins.GetItemsWithFilterAndOrdering( + skin => true, + index, count, orderingPropertyName, descending); + + private static Func filterByChampion = (skin, champion) => champion != null && skin.Champion.Equals(champion!); + + private static Func filterByName = (skin, substring) => skin.Name.Contains(substring, StringComparison.InvariantCultureIgnoreCase); + + public Task> GetItemsByChampion(Champion? champion, int index, int count, string? orderingPropertyName = null, bool descending = false) + => parent.skins.GetItemsWithFilterAndOrdering( + skin => filterByChampion(skin, champion), + index, count, orderingPropertyName, descending); + + public Task> GetItemsByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false) + => parent.skins.GetItemsWithFilterAndOrdering( + skin => filterByName(skin, substring), + index, count, orderingPropertyName, descending); + + public Task GetNbItems() + => parent.skins.GetNbItemsWithFilter( + c => true); + + public Task GetNbItemsByChampion(Champion? champion) + => parent.skins.GetNbItemsWithFilter( + skin => filterByChampion(skin, champion)); + + public Task GetNbItemsByName(string substring) + => parent.skins.GetNbItemsWithFilter( + skin => filterByName(skin, substring)); + + public Task UpdateItem(Skin? oldItem, Skin? newItem) + => parent.skins.UpdateItem(oldItem, newItem); + } + } +} + diff --git a/src/EntityFramework_LoL/Sources/StubLib/StubData.cs b/src/EntityFramework_LoL/Sources/StubLib/StubData.cs new file mode 100644 index 0000000..8e34486 --- /dev/null +++ b/src/EntityFramework_LoL/Sources/StubLib/StubData.cs @@ -0,0 +1,35 @@ +using Model; + +namespace StubLib; +public partial class StubData : IDataManager +{ + public StubData() + { + ChampionsMgr = new ChampionsManager(this); + SkinsMgr = new SkinsManager(this); + RunesMgr = new RunesManager(this); + RunePagesMgr = new RunePagesManager(this); + + InitSkins(); + InitRunePages(); + } + + public IChampionsManager ChampionsMgr { get; } + + public ISkinsManager SkinsMgr { get; } + + public IRunesManager RunesMgr { get; } + + public IRunePagesManager RunePagesMgr { get; } + + private List> championsAndRunePages = new(); + + private void InitChampionsAndRunePages() + { + championsAndRunePages.Add(Tuple.Create(champions[0], runePages[0])); + } + + + +} + diff --git a/src/EntityFramework_LoL/Sources/StubLib/StubLib.csproj b/src/EntityFramework_LoL/Sources/StubLib/StubLib.csproj new file mode 100644 index 0000000..f05027c --- /dev/null +++ b/src/EntityFramework_LoL/Sources/StubLib/StubLib.csproj @@ -0,0 +1,12 @@ + + + + net6.0 + enable + enable + + + + + + diff --git a/src/EntityFramework_LoL/Sources/Tests/ConsoleTests/ConsoleTests.csproj b/src/EntityFramework_LoL/Sources/Tests/ConsoleTests/ConsoleTests.csproj new file mode 100644 index 0000000..1602b94 --- /dev/null +++ b/src/EntityFramework_LoL/Sources/Tests/ConsoleTests/ConsoleTests.csproj @@ -0,0 +1,20 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + + + + + + + diff --git a/src/EntityFramework_LoL/Sources/Tests/ConsoleTests/Program.cs b/src/EntityFramework_LoL/Sources/Tests/ConsoleTests/Program.cs new file mode 100644 index 0000000..28dc26b --- /dev/null +++ b/src/EntityFramework_LoL/Sources/Tests/ConsoleTests/Program.cs @@ -0,0 +1,338 @@ +using System.Collections.Immutable; +using System.Diagnostics; +using Microsoft.Extensions.DependencyInjection; +using Model; +using StubLib; +using static System.Console; + +namespace ConsoleTests +{ + static class Program + { + static IDataManager dataManager = null!; + + static async Task Main(string[] args) + { + try + { + using var servicesProvider = new ServiceCollection() + .AddSingleton() + .BuildServiceProvider(); + + dataManager = servicesProvider.GetRequiredService(); + + await DisplayMainMenu(); + + Console.ReadLine(); + } + catch (Exception ex) + { + Debug.WriteLine(ex, "Stopped program because of exception"); + throw; + } + } + + public static async Task DisplayMainMenu() + { + Dictionary choices = new Dictionary() + { + [1] = "1- Manage Champions", + [2] = "2- Manage Skins", + [3] = "3- Manage Runes", + [4] = "4- Manage Rune Pages", + [99] = "99- Quit" + }; + + while(true) + { + int input = DisplayAMenu(choices); + + switch(input) + { + case 1: + await DisplayChampionsMenu(); + break; + case 2: + break; + case 3: + break; + case 4: + break; + case 99: + WriteLine("Bye bye!"); + return; + default: + break; + } + } + } + + private static int DisplayAMenu(Dictionary choices) + { + int input=-1; + while(true) + { + WriteLine("What is your choice?"); + WriteLine("--------------------"); + foreach(var choice in choices.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value)) + { + WriteLine(choice); + } + if(!int.TryParse(ReadLine(), out input) || input == -1) + { + WriteLine("I do not understand what your choice is. Please try again."); + continue; + } + break; + } + WriteLine($"You have chosen: {choices[input]}"); + WriteLine(); + return input; + } + + public static async Task DisplayChampionsMenu() + { + Dictionary choices = new Dictionary() + { + [0] = "0- Get number of champions", + [1] = "1- Get champions", + [2] = "2- Find champions by name", + [3] = "3- Find champions by characteristic", + [4] = "4- Find champions by class", + [5] = "5- Find champions by skill", + [6] = "6- Add new champion", + [7] = "7- Delete a champion", + [8] = "8- Update a champion", + }; + + int input = DisplayAMenu(choices); + + switch(input) + { + case 0: + int nb = await dataManager.ChampionsMgr.GetNbItems(); + WriteLine($"There are {nb} champions"); + WriteLine("**********************"); + break; + case 1: + { + int index = ReadAnInt("Please enter the page index"); + int count = ReadAnInt("Please enter the number of elements to display"); + WriteLine($"{count} champions of page {index+1}"); + var champions = await dataManager.ChampionsMgr.GetItems(index, count, nameof(Champion.Name)); + foreach(var champion in champions) + { + WriteLine($"\t{champion}"); + } + WriteLine("**********************"); + } + break; + case 2: + { + string substring = ReadAString("Please enter the substring to look for in the name of a champion"); + int index = ReadAnInt("Please enter the page index"); + int count = ReadAnInt("Please enter the number of elements to display"); + var champions = await dataManager.ChampionsMgr.GetItemsByName(substring, index, count, nameof(Champion.Name)); + foreach(var champion in champions) + { + WriteLine($"\t{champion}"); + } + WriteLine("**********************"); + } + break; + case 3: + { + string substring = ReadAString("Please enter the substring to look for in the characteristics of champions"); + int index = ReadAnInt("Please enter the page index"); + int count = ReadAnInt("Please enter the number of elements to display"); + var champions = await dataManager.ChampionsMgr.GetItemsByCharacteristic(substring, index, count, nameof(Champion.Name)); + foreach(var champion in champions) + { + WriteLine($"\t{champion}"); + } + WriteLine("**********************"); + } + break; + case 4: + { + ChampionClass championClass = ReadAnEnum($"Please enter the champion class (possible values are: {Enum.GetNames().Aggregate("", (name, chaine) => $"{chaine} {name}")}):"); + int index = ReadAnInt("Please enter the page index"); + int count = ReadAnInt("Please enter the number of elements to display"); + var champions = await dataManager.ChampionsMgr.GetItemsByClass(championClass, index, count, nameof(Champion.Name)); + foreach(var champion in champions) + { + WriteLine($"\t{champion}"); + } + WriteLine("**********************"); + } + break; + case 5: + { + string substring = ReadAString("Please enter the substring to look for in the skills of champions"); + int index = ReadAnInt("Please enter the page index"); + int count = ReadAnInt("Please enter the number of elements to display"); + var champions = await dataManager.ChampionsMgr.GetItemsBySkill(substring, index, count, nameof(Champion.Name)); + foreach(var champion in champions) + { + WriteLine($"\t{champion}"); + } + WriteLine("**********************"); + } + break; + case 6: + { + WriteLine("You are going to create a new champion."); + string name = ReadAString("Please enter the champion name:"); + ChampionClass championClass = ReadAnEnum($"Please enter the champion class (possible values are: {Enum.GetNames().Aggregate("", (name, chaine) => $"{chaine} {name}")}):"); + string bio = ReadAString("Please enter the champion bio:"); + Champion champion = new Champion(name, championClass, bio: bio); + DisplayCreationChampionMenu(champion); + _ = await dataManager.ChampionsMgr.AddItem(champion); + } + break; + case 7: + { + WriteLine("You are going to delete a champion."); + string name = ReadAString("Please enter the champion name:"); + var somechampions = await dataManager.ChampionsMgr.GetItemsByName(name, 0, 10, nameof(Champion.Name)); + var someChampionNames = somechampions.Select(c => c!.Name); + var someChampionNamesAsOneString = someChampionNames.Aggregate("", (name, chaine) => $"{chaine} {name}"); + string champName = ReadAStringAmongPossibleValues($"Who do you want to delete among these champions? (type \"Cancel\" to ... cancel) {someChampionNamesAsOneString}", + someChampionNames.ToArray()); + if(champName != "Cancel") + { + await dataManager.ChampionsMgr.DeleteItem(somechampions.Single(c => c!.Name == champName)); + } + } + break; + case 8: + { + WriteLine("You are going to update a champion."); + string name = ReadAString("Please enter the champion name:"); + var somechampions = await dataManager.ChampionsMgr.GetItemsByName(name, 0, 10, nameof(Champion.Name)); + var someChampionNames = somechampions.Select(c => c!.Name); + var someChampionNamesAsOneString = someChampionNames.Aggregate("", (name, chaine) => $"{chaine} {name}"); + string champName = ReadAStringAmongPossibleValues($"Who do you want to update among these champions? (type \"Cancel\" to ... cancel) {someChampionNamesAsOneString}", + someChampionNames.ToArray()); + if(champName == "Cancel") break; + ChampionClass championClass = ReadAnEnum($"Please enter the champion class (possible values are: {Enum.GetNames().Aggregate("", (name, chaine) => $"{chaine} {name}")}):"); + string bio = ReadAString("Please enter the champion bio:"); + Champion champion = new Champion(champName, championClass, bio: bio); + DisplayCreationChampionMenu(champion); + await dataManager.ChampionsMgr.UpdateItem(somechampions.Single(c => c!.Name == champName), champion); + } + break; + default: + break; + } + + } + + public static void DisplayCreationChampionMenu(Champion champion) + { + Dictionary choices = new Dictionary() + { + [1] = "1- Add a skill", + [2] = "2- Add a skin", + [3] = "3- Add a characteristic", + [99] = "99- Finish" + }; + + while(true) + { + int input = DisplayAMenu(choices); + + switch(input) + { + case 1: + string skillName = ReadAString("Please enter the skill name:"); + SkillType skillType = ReadAnEnum($"Please enter the skill type (possible values are: {Enum.GetNames().Aggregate("", (name, chaine) => $"{chaine} {name}")}):"); + string skillDescription = ReadAString("Please enter the skill description:"); + Skill skill = new Skill(skillName, skillType, skillDescription); + champion.AddSkill(skill); + break; + case 2: + string skinName = ReadAString("Please enter the skin name:"); + string skinDescription = ReadAString("Please enter the skin description:"); + float skinPrice = ReadAFloat("Please enter the price of this skin:"); + Skin skin = new Skin(skinName, champion, skinPrice, description: skinDescription); + break; + case 3: + string characteristic = ReadAString("Please enter the characteristic:"); + int value = ReadAnInt("Please enter the value associated to this characteristic:"); + champion.AddCharacteristics(Tuple.Create(characteristic, value)); + break; + case 99: + return; + default: + break; + } + } + } + + private static int ReadAnInt(string message) + { + while(true) + { + WriteLine(message); + if(!int.TryParse(ReadLine(), out int result)) + { + continue; + } + return result; + } + } + + private static float ReadAFloat(string message) + { + while(true) + { + WriteLine(message); + if(!float.TryParse(ReadLine(), out float result)) + { + continue; + } + return result; + } + } + + private static string ReadAString(string message) + { + while(true) + { + WriteLine(message); + string? line = ReadLine(); + if(line == null) + { + continue; + } + return line!; + } + } + + private static TEnum ReadAnEnum(string message) where TEnum :struct + { + while(true) + { + WriteLine(message); + if(!Enum.TryParse(ReadLine(), out TEnum result)) + { + continue; + } + return result; + } + } + + private static string ReadAStringAmongPossibleValues(string message, params string[] possibleValues) + { + while(true) + { + WriteLine(message); + string? result = ReadLine(); + if(result == null) continue; + if(result != "Cancel" && !possibleValues.Contains(result!)) continue; + return result!; + } + } + } +} \ No newline at end of file