Стефани обнови решението на 05.12.2015 02:02 (преди над 2 години)
+package main
+
+import (
+ "encoding/json"
+ "encoding/xml"
+ "fmt"
+)
+
+type Library interface {
+
+ // Добавя книга от json
+ // Oтговаря с общия брой копия в библиотеката (не само наличните).
+ // Aко са повече от 4 - връща грешка
+ AddBookJSON(data []byte) (int, error)
+
+ // Добавя книга от xml
+ // Oтговаря с общия брой копия в библиотеката (не само наличните).
+ // Ако са повече от 4 - връщаме грешка
+ AddBookXML(data []byte) (int, error)
+
+ // Ангажира свободен "библиотекар" да ни обработва заявките.
+ // Библиотекарите са фиксиран брой - подават се като параметър на NewLibrary
+ // Блокира ако всички библиотекари са заети.
+ // Връщат се два канала:
+ // първият е само за писане - по него ще изпращаме заявките
+ // вторият е само за четене - по него ще получаваме отговорите.
+ // Ако затворим канала със заявките - освобождаваме библиотекаря.
+ Hello() (chan<- LibraryRequest, <-chan LibraryResponse)
+}
+
+type LibraryRequest interface {
+ // Тип на заявката:
+ // 1 - Borrow book
+ // 2 - Return book
+ // 3 - Get availability information about book
+ GetType() int
+
+ // Връща isbn на книгата, за която се отнася Request-a
+ GetISBN() string
+}
+
+type LibraryResponse interface {
+ // Ако книгата съществува/налична е - обект имплементиращ fmt.Stringer (повече информация по-долу)
+ // Aко книгата не съществува първият резултат е nil.
+ // Връща се и подобаващa грешка (виж по-долу) - ако такава е възникнала.
+ // Когато се е резултат на заявка от тип 2 (Return book) - не е нужно да я закачаме към отговора.
+ GetBook() (fmt.Stringer, error)
+
+ // available - Колко наличности от книгата имаме останали след изпълнението на заявката.
+ // Тоест, ако сме имали 3 копия от Х и това е отговор на Borrow заявка - тук ще има 2.
+ // registered - Колко копия от тази книга има регистрирани в библиотеката (макс 4).
+ GetAvailability() (available int, registered int)
+}
+
+type MyRequest struct {
+ reqType int
+ isbn string
+}
+
+func (req MyRequest) GetType() int {
+ return req.reqType
+}
+
+func (req MyRequest) GetISBN() string {
+ return req.isbn
+}
+
+type MyResponse struct {
+ book Book
+ availability int
+ registered int
+ error string
+}
+
+func (response MyResponse) GetBook() (fmt.Stringer, error) {
+ if response.error != "" {
+ return nil, errorString{response.error}
+ }
+ return response.book, nil
+}
+
+func (book Book) String() string {
+ return "[" + book.Isbn + "] " + book.Title + " от " + book.Author.FirstName + " " + book.Author.LastName
+}
+
+func (response MyResponse) GetAvailability() (available int, registered int) {
+ return response.availability, response.registered
+}
+
+// Връща "отворена" библиотека
+func NewLibrary(librarians int) Library {
+ return &MyLibrary{
+ allLibrarians: librarians,
+ busyLibrarians: 0,
+ books: []Book{},
+ bookAvailable: map[string]int{},
+ bookRegistered: map[string]int{},
+ }
+}
+
+type Author struct {
+ FirstName string `json:"first_name" xml:"first_name"`
+ LastName string `json:"last_name" xml:"last_name"`
+}
+
+type Book struct {
+ Isbn string `json:"isbn" xml:"isbn,attr"`
+ Author Author `json:"author" xml:"author"`
+ Title string `json:"title" xml:"title"`
+ Ratings []int `json:"ratings" xml:"ratings>rating"`
+}
+
+type MyLibrary struct {
+ allLibrarians int
+ busyLibrarians int
+ books []Book
+ bookAvailable map[string]int
+ bookRegistered map[string]int
+}
+
+func (library *MyLibrary) AddBookJSON(data []byte) (int, error) {
+ var book Book
+ json.Unmarshal(data, &book)
+ val, ok := library.bookRegistered[book.Isbn]
+ if !ok {
+ library.books = append(library.books, book)
+ } else if val >= 4 {
+ return val, errorString{"Има 4 копия на книга <" + book.Isbn + ">"}
+ }
+
+ library.bookRegistered[book.Isbn]++
+ library.bookAvailable[book.Isbn]++
+ return library.bookRegistered[book.Isbn], nil
+}
+
+func (library *MyLibrary) AddBookXML(data []byte) (int, error) {
+ var book Book
+ xml.Unmarshal(data, &book)
+ val, ok := library.bookRegistered[book.Isbn]
+ if !ok {
+ library.books = append(library.books, book)
+ } else if val >= 4 {
+ return val, errorString{"Има 4 копия на книга " + book.Isbn}
+ }
+
+ library.bookRegistered[book.Isbn]++
+ library.bookAvailable[book.Isbn]++
+ return library.bookRegistered[book.Isbn], nil
+}
+
+type errorString struct {
+ errorMsg string
+}
+
+func (e errorString) Error() string {
+ return e.errorMsg
+}
+
+func (library *MyLibrary) Hello() (chan<- LibraryRequest, <-chan LibraryResponse) {
+ if library.allLibrarians-library.busyLibrarians >= 0 {
+ //blokira
+ } else {
+ library.busyLibrarians++
+ }
+ in := make(chan LibraryRequest)
+ out := make(chan LibraryResponse)
+ go func() {
+ for req := range in {
+ if req.GetType() == 1 { //borrow
+ resp := MyResponse{
+
+ availability: library.bookAvailable[req.GetISBN()],
+ registered: library.bookRegistered[req.GetISBN()],
+ error: "",
+ }
+
+ if resp.registered == 0 {
+ resp.error = "Непозната книга " + req.GetISBN()
+ } else if resp.availability <= 0 {
+ resp.error = "Няма наличност на книга " + req.GetISBN()
+ } else {
+ for _, book := range library.books {
+ if book.Isbn == req.GetISBN() {
+ resp.book = book
+ break
+ }
+ library.bookAvailable[req.GetISBN()]--
+ resp.availability--
+ }
+ }
+
+ out <- resp
+
+ } else if req.GetType() == 2 { //return
+
+ resp := MyResponse{
+
+ availability: library.bookAvailable[req.GetISBN()],
+ registered: library.bookRegistered[req.GetISBN()],
+ error: "",
+ }
+
+ if resp.registered == 0 {
+ resp.error = "Непозната книга " + req.GetISBN()
+ } else if resp.registered-resp.availability <= 0 {
+ resp.error = "Всички копия са налични " + req.GetISBN()
+ } else {
+ for _, book := range library.books {
+ if book.Isbn == req.GetISBN() {
+ resp.book = book
+ break
+ }
+ library.bookAvailable[req.GetISBN()]++
+ resp.availability++
+ }
+ }
+
+ out <- resp
+
+ } else if req.GetType() == 3 {
+ resp := MyResponse{
+
+ availability: library.bookAvailable[req.GetISBN()],
+ registered: library.bookRegistered[req.GetISBN()],
+ error: "",
+ }
+
+ if resp.registered == 0 {
+ resp.error = "Непозната книга " + req.GetISBN()
+ } else {
+ for _, book := range library.books {
+ if book.Isbn == req.GetISBN() {
+ resp.book = book
+ break
+ }
+ }
+ }
+
+ out <- resp
+ }
+ }
+ }()
+
+ return in, out
+}