+ **در این سوال به هر بخش از سوال که پاسخ بدهید نمره همان قسمت را خواهید گرفت**
+ **این سوال را باید با زبان جاوا پاسخ دهید. دقت کنید که انتظار نمیرود که همه مفاهیم را از ابتدا بلد باشید و ممکن است بسته به توانایی خود نیاز به جستوجو کردن داشته باشید.**
----------
قرار است در نیمبو یک فضای ابری برای ذخیره سازی فایلها به اسم *NimboDrive* بسازیم! کلاسها و توابع اولیه این برنامه را نوشته ایم اما این وظیفه شماست که آنها را پیادهسازی و کامل کنید.
فایلهای اولیه پروژه را از [اینجا](https://quera.ir/qbox/download/hgEs31dkYH/NimboDrive.zip) دانلود کنید.
دقت کنید که نیازی نیست کل کارهای گفته شده در یک قسمت را انجام دهید تا نمره آن قسمت را بگیرید. در هر قسمت هر بخشی را که پیادهسازی کنید، نمره همان بخش را خواهیدگرفت. نحوه آپلود جواب در انتهای سوال آورده شده است.
--------
## قسمت اول
در این قسمت شما باید کلاس `UserStorageRepository` را پیادهسازی کنید. این کلاس مدیریت میکند که هر کاربر چقدر حجم برای ذخیره سازی فایل در سیستم ما دارد. این کلاس برای اینکار در داخل خود یک *Map* از اسم کاربر و حجم دارد.
برای مثال در خود ذخیره میکند که کاربری به اسم `Ali` میتواند 125000 بایت دیگر در سیستم فایل آپلود کند.
توابع گفته شده در زیر را پیادهسازی کنید. (**روی عنوان هر کار کلیک کنید تا توضیحات آن باز شود**.)
<details>
<summary>
تابع increaseStorageOfUser
</summary>
این تابع اسم کاربر و یک عدد گرفته و میزان حجم کاربر را به اندازه عدد داده شده زیاد میکند. اگر کاربر از قبل در *Map* وجود نداشته باشد آن را اضافه میکند و حجم آن را برابر با مقدار داده شده قرار میدهد.
</details>
<details>
<summary>
تابع hasStorage
</summary>
این تابع اسم کاربر و یک عدد گرفته و بررسی میکند آیا کاربر به اندازه داده شده حجم دارد یا نه. اگر کاربر کلا وجود نداشته باشد باید `false` برگردانده شود.
</details>
<details>
<summary>
تابع decreaseStorageOfUser
</summary>
این تابع اسم کاربر و یک عدد گرفته و حجم کاربر را به آن اندازه کم میکند. اگر حجم کاربر به صفر رسید یا منفی شد، آن کاربر از *Map* حذف میشود.
</details>
--------
## قسمت دوم
کلاس `NimboFile` یک فایل را در سیستم ما مشخص میکند. این کلاس، زیرکلاسهایی(مثل `TextFile`) دارد که نوع فایل را مشخص میکنند. هر فایل یک اسم(مثلا `readme.txt`)، یک پوشه (مثلا `/user/ali/`) ، یک مالک (مثلا `Ali`) و یک عدد به عنوان حجم دارد که واحد آن بایت است.
کلاس `FileRepository` کلاس اصلی برای مدیریت فایلهاست که در آن کل فایلها و اطلاعات آنها ذخیره میشود.
شما باید کارهای گفته شده در زیر را انجام دهید.
<details>
<summary>
نوشتن متد `toString` برای `NimboFile`
</summary>
در کلاس `NimboFile` متد `toString` را override کنید به طوری که اسم کامل فایل(مثلا `a.txt`) را برگرداند.
</details>
<details>
<summary>
پیادهسازی تابع `addFile` در کلاس `FileRepository`
</summary>
این تابع یک فایل به عنوان ورودی میگیرد و اگر مالک فایل به اندازه کافی حجم داشته باشد، فایل را به مجموعه فایلهای ذخیره شده اضافه میکند و به اندازه حجم فایل از فضای مالک کم میکند.
اگر مالک فایل به اندازه کافی حجم نداشته باشد باید یک استنا از نوع *IllegalArgumentException* پرتاب کنید.
درون این کلاس یک شی از جنس `UserStorageRepository` وجود دارد که برای کمکردن حجم از کاربر باید از آن استفاده کنید.
</details>
<details>
<summary>
پیادهسازی تابع `searchByName` در کلاس `FileRepository`
</summary>
این تابع یک رشته دریافت کرده و لیست تمام فایلهایی که رشته داده شده در اسم آنها تکرار شدهاست را بر میگرداند. دقت کنید که فرمت فایل نباید در جست و جو در نظر گرفته شود. برای مثال اگر اسم فایل `a.txt` باشد و `xt` را سرچ کنیم، این فایل نباید برگرداننده شود. **جست و جو حساس به حروف بزرگ و کوچک نیست.**
</details>
<details>
<summary>
پیادهسازی تابع `scan` در کلاس `FileRepository`
</summary>
یک شئ در این کلاس به اسم `scanner` وجود دارد. این شئ یک تابع به اسم `scanFile` دارد که یک فایل ورودی میگیرد و اگر فایل ویروسی باشد یک اکسپشن پرت میکند. این تابع به کمک این شئ تمام فایلها را اسکن میکند و فایلهایی که عادی نیستند را از مجموعه فایلها حذف میکند و حجم آنها را به مالکان فایلها بر میگرداند.
</details>
--------
## قسمت سوم
برنامه ما این قابلیت را دارد که بعضی از انواع فایلها را بدون دانلود به صورت پیشنمایش به کاربر نشان دهد. فایلی که این قابلیت را دارد واسط `hasPreview` را پیادهسازی میکند.
<details>
<summary>
اضافه کردن پیشنمایش به کلاس `TextFile`
</summary>
کلاس `TextFile` را عوض کنید به گونهای که اینترفیسِ `HasPreview<String>` را پیادهسازی کند.دقت کنید که نیازی نیست در این بخش تابع `preview` را هم پیادهسازی کنید. برای سادگی فعلاً میتوانید در آن `return null;` بگذارید.
</details>
<details>
<summary>
پیادهسازی تابع `isPreviewable` در کلاس `FileRepository`
</summary>
این تابع یک فایل میگیرد و اگر فایل داده شده اینترفیسِ `HasPreview` را پیادهسازی کرده باشد (یا به عبارت دیگر از جنس `HasPreview` باشد ) `true` بر میگرداند.
</details>
<details>
<summary>
پیادهسازی تابع `sort` در کلاس `FileRepository`
</summary>
این تابع یک *Comparator* به عنوان ورودی میگیرد و فایلها را با توجه به آن مرتب کرده به صورت آرایه بر میگرداند.
</details>
--------
## قسمت چهارم
<details>
<summary>
پیادهسازی تابع `findLongestMediaInDirectory` در کلاس `FileRepository`
</summary>
این تابع آدرس یک پوشه را میگیرد(مثلا `/home/ali/`) و طولانیترین فایل درون آن پوشه که از جنس `MediaFile` باشد را درون یک `Optional` گذاشته و برمیگرداند. طولانیترین فایل، فایلی است که `duration` آن از همه بیشتر باشد. اگر در آن پوشه هیج فایل مدیایی وجود نداشته باشد `Optional.empty()` برگردانده میشود. همچنین اگر چندین فایل با طول یکسان وجود داشت یکی از آنها به دلخواه باید برگرداننده شود.
</details>
<details>
<summary>
پیادهسازی پیشنمایش برای کلاس `TextFile`
</summary>
در قسمت قبل کلاس `TextFile` را عوض کردید به گونهای که اینترفیسِ `HasPreview<String>` را پیادهسازی کند. در این بخش باید تابع `preview` را در این کلاس پیادهسازی کنید. این تابع یک `InputStream` که مربوط به این فایل متنی است را دریافت میکند و باید خط اول آن را بخواند و رشته خوانده شده را در کلاس Preview قرار دهد و آن را برگرداند.
</details>
<details>
<summary>
پیادهسازی تابع `applyToAllByFilter` در کلاس `FileRepository`
</summary>
این تابع یک فیلتر و یک تابع به عنوان ورودی گرفته و تابع گرفته شده را روی تمامی فایلهایی که با فیلتر مطابقت دارند(فیلتر به ازای آنها true برمیگرداند) اعمال میکند.
</details>
--------------------------
## نکات
+ یک فایل به اسم `SampleMain.java` به شما داده شده است تا با نحوه ی کارکردن کلاسها آشنا شوید و استفاده دیگری ندارد.
+ به هیچ وجه امضای توابع داده شده یا متغیر های درونی هر کلاس را عوض نکنید. تغییر اسم تابع، نوع برگشتی، پارامترها و ... باعث میشود کد شما داوری نشود.
+ دقت کنید حتی اگر بعضی از فایلها را هنوز دست نزدهاید باز هم باید آنها را مطابق الگوی زیر آپلود کنید تا کد شما کامپایل شود و مورد داوری قرارگیرد.
**چیزی که باید آپلود کنید:** یک فایل زیپ دقیقاً مشابه فایلی که دریافت کردید، یعنی وقتی آن را باز میکنیم پوشه in را ببینیم. داخل پوشه `in` باید پوشه `nimbo` قرار گرفته باشد. داخل پوشه `nimbo` هم باید پوشههای `file` و `preview` و فایلهای `UserStorageRepository.java` و `FileRepository.java` و `FileScanner.java` قرار گرفته باشند. درون پوشههای `file` و `preview` نیز باید فایلهای مرتبط موجود باشند. اسم فایل زیپ مهم نیست. ساختاری مشابه شکل زیر:
```
yourZipFileName.zip
└── in
└── nimbo
├── file
│ ├── BinaryFile.java
│ ├── MediaFile.java
│ ├── NimboFile.java
│ └── TextFile.java
├── FileRepository.java
├── FileScanner.java
├── preview
│ ├── hasPreview.java
│ └── Preview.java
├── SampleMain.java
└── UserStorageRepository.java
```