Ангел обнови решението на 05.12.2015 00:07 (преди над 2 години)
+package main
+
+import (
+ "encoding/json"
+ "encoding/xml"
+ "fmt"
+ "sync"
+)
+
+type Library interface {
+ AddBookJSON(data []byte) (int, error)
+ AddBookXML(data []byte) (int, error)
+ Hello() (chan<- LibraryRequest, <-chan LibraryResponse)
+}
+
+type LibraryRequest interface {
+ GetType() int
+ GetISBN() string
+}
+
+type LibraryResponse interface {
+ GetBook() (fmt.Stringer, error)
+ GetAvailability() (available int, registered int)
+}
+
+type BookAuthor struct {
+ XMLName xml.Name `xml:"author"`
+ FirstName string `json:"first_name" xml:"first_name"`
+ LastName string `json:"last_name" xml:"last_name"`
+}
+
+func (a *BookAuthor) String() string {
+ return fmt.Sprintf("%s %s", a.FirstName, a.LastName)
+}
+
+type Book struct {
+ XMLName xml.Name `xml:"book"`
+ Isbn string `json:"isbn" xml:"isbn,attr"`
+ Title string `json:"title" xml:"title"`
+ Author *BookAuthor `json:"author" xml:"author"`
+}
+
+func (b *Book) String() string {
+ return fmt.Sprintf("[%s] %s от %s", b.Isbn, b.Title, b.Author)
+}
+
+type MyLibrary struct {
+ books map[string]*Book
+ copies map[string]int
+ available map[string]int
+ librarians int
+ requestMutex *sync.Mutex
+}
+
+func NewLibrary(librarians int) Library {
+ library := MyLibrary{}
+ library.books = make(map[string]*Book, 0)
+ library.copies = make(map[string]int)
+ library.available = make(map[string]int)
+ library.librarians = librarians
+ library.requestMutex = new(sync.Mutex)
+ return library
+}
+
+func (m MyLibrary) AddBookJSON(data []byte) (int, error) {
+ book := new(Book)
+ err := json.Unmarshal(data, book)
+ if err != nil {
+ return 0, err
+ }
+ return m.addBook(book)
+}
+
+func (m MyLibrary) AddBookXML(data []byte) (int, error) {
+ book := new(Book)
+ err := xml.Unmarshal(data, book)
+ if err != nil {
+ return 0, err
+ }
+ return m.addBook(book)
+}
+
+type MyRequest struct {
+ requestType int
+ requestIsbn string
+}
+
+func (m MyRequest) GetType() int {
+ return m.requestType
+}
+
+func (m MyRequest) GetISBN() string {
+ return m.requestIsbn
+}
+
+type MyResponse struct {
+ book *Book
+ err error
+ available int
+ registered int
+}
+
+func (m MyResponse) GetBook() (fmt.Stringer, error) {
+ return m.book, m.err
+}
+
+func (m MyResponse) GetAvailability() (available int, registered int) {
+ return m.available, m.registered
+}
+
+func (m *MyLibrary) addBook(book *Book) (int, error) {
+ m.requestMutex.Lock()
+ defer m.requestMutex.Unlock()
+
+ m.books[book.Isbn] = book
+ if m.copies[book.Isbn] >= 4 {
+ return 0, fmt.Errorf("Има 4 копия на книга %s", book.Isbn)
+ }
+ m.copies[book.Isbn]++
+ m.available[book.Isbn]++
+ return m.copies[book.Isbn], nil
+}
+
+func (m *MyLibrary) handle(request LibraryRequest) LibraryResponse {
+ m.requestMutex.Lock()
+ defer m.requestMutex.Unlock()
+
+ response := MyResponse{}
+ isbn := request.GetISBN()
+
+ book := m.books[isbn]
+ if book == nil {
+ response.err = fmt.Errorf("Непозната книга %s", isbn)
+ return response
+ }
+
+ switch request.GetType() {
+ case 1:
+ if m.available[isbn] > 0 {
+ m.available[isbn]--
+ } else {
+ response.err = fmt.Errorf("Няма наличност на книга %s", isbn)
+ }
+ case 2:
+ if m.available[isbn] < m.copies[isbn] {
+ m.available[isbn]++
+ } else {
+ response.err = fmt.Errorf("Всички копия са налични %s", isbn)
+ }
+ }
+
+ response.book = book
+ response.available = m.available[isbn]
+ response.registered = m.copies[isbn]
+ return response
+}
+
+func (m *MyLibrary) librarian(requests chan LibraryRequest,
+ responses chan LibraryResponse) {
+ for request := range requests {
+ responses <- m.handle(request)
+ }
+ return
+}
+
+func (m MyLibrary) Hello() (chan<- LibraryRequest, <-chan LibraryResponse) {
+ requests := make(chan LibraryRequest)
+ responses := make(chan LibraryResponse)
+ for i := 0; i < m.librarians; i++ {
+ go m.librarian(requests, responses)
+ }
+ return requests, responses
+}