Ангел обнови решението на 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
+}
