Диана обнови решението на 03.12.2015 20:37 (преди над 2 години)
+package main
+
+import (
+        "encoding/json"
+        "encoding/xml"
+        "fmt"
+)
+
+const (
+        _ = iota
+        TakeBook
+        ReturnBook
+        CheckAvailability
+)
+
+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 TheLibraryRequest struct {
+        Isbn string
+        Type int
+}
+
+func (t TheLibraryRequest) GetType() int {
+        return t.Type
+}
+
+func (t TheLibraryRequest) GetISBN() string {
+        return t.Isbn
+}
+
+type LibraryResponse interface {
+        GetBook() (fmt.Stringer, error)
+        GetAvailability() (available int, registered int)
+}
+
+type TheLibraryResponse struct {
+        book                              *Book
+        isbn                              string
+        err                               error
+        availableNumber, registeredNumber int
+}
+
+func (t TheLibraryResponse) GetBook() (fmt.Stringer, error) {
+        if t.book == nil {
+                return t.book, fmt.Errorf("Непозната книга %s", t.isbn)
+        }
+        return t.book, t.err
+}
+
+func (t TheLibraryResponse) GetAvailability() (available int, registered int) {
+        return t.availableNumber, t.registeredNumber
+}
+
+type AuthorName struct {
+        XMLName   xml.Name `xml:"author"`
+        FirstName string   `json:"first_name" xml:"first_name"`
+        LastName  string   `json:"last_name" xml:"last_name"`
+}
+
+func (a *AuthorName) String() string {
+        return a.FirstName + " " + a.LastName
+}
+
+type Book struct {
+        XMLName xml.Name    `xml:"book"`
+        Isbn    string      `xml:"isbn,attr" json:"isbn"`
+        Author  *AuthorName `json:"author"`
+        Title   string      `json:"title" xml:"title"`
+        Ratings []int       `json:"rating" xml:"ratings>rating"`
+}
+
+func newBook() *Book {
+        return &Book{Ratings: make([]int, 0)}
+}
+
+func (b *Book) String() string {
+        return fmt.Sprintf("[%s] %s от %s", b.Isbn, b.Title, b.Author)
+}
+
+type TheLibrary struct {
+        books          *[]*Book
+        AvailableBooks map[string]int
+        librarians     int
+        BorrowedBooks  map[string]int
+}
+
+func (l TheLibrary) GetBook(isbn string) *Book {
+        for _, book := range *l.books {
+                if book.Isbn == isbn {
+                        return book
+                }
+        }
+        return nil
+}
+
+func (l TheLibrary) AddBook(data []byte, unmarshal func([]byte, interface{}) error) (int, error) {
+        var newBook Book
+        err := unmarshal(data, &newBook)
+        if err != nil {
+                return l.AvailableBooks[newBook.Isbn] + l.BorrowedBooks[newBook.Isbn], err
+        }
+        *l.books = append(*l.books, &newBook)
+        if l.AvailableBooks[newBook.Isbn]+l.BorrowedBooks[newBook.Isbn] < 4 {
+                l.AvailableBooks[newBook.Isbn]++
+                return l.AvailableBooks[newBook.Isbn] + l.BorrowedBooks[newBook.Isbn], nil
+        }
+        return 4, fmt.Errorf("Има 4 копия на книга %s", newBook.Isbn)
+}
+
+func (l TheLibrary) AddBookJSON(data []byte) (int, error) {
+        return l.AddBook(data, json.Unmarshal)
+}
+
+func (l TheLibrary) AddBookXML(data []byte) (int, error) {
+        return l.AddBook(data, xml.Unmarshal)
+}
+
+func (l TheLibrary) Hello() (chan<- LibraryRequest, <-chan LibraryResponse) {
+        resChannel := make(chan LibraryResponse)
+        reqChannel := make(chan LibraryRequest)
+        for i := 0; i < l.librarians; i++ {
+                go l.HandleRequest(reqChannel, resChannel)
+        }
+        return reqChannel, resChannel
+}
+
+func (l TheLibrary) HandleRequest(reqChannel chan LibraryRequest, resChannel chan LibraryResponse) {
+        for request := range reqChannel {
+                isbn := request.GetISBN()
+                switch request.GetType() {
+                case TakeBook:
+                        if l.AvailableBooks[isbn] > 0 {
+                                l.AvailableBooks[isbn]--
+                                l.BorrowedBooks[isbn]++
+                                resChannel <- &TheLibraryResponse{book: l.GetBook(isbn),
+                                        isbn: isbn, availableNumber: l.AvailableBooks[isbn],
+                                        registeredNumber: l.AvailableBooks[isbn] + l.BorrowedBooks[isbn],
+                                        err:              nil,
+                                }
+                        } else {
+                                resChannel <- &TheLibraryResponse{book: l.GetBook(isbn),
+                                        isbn: isbn, availableNumber: l.AvailableBooks[isbn],
+                                        registeredNumber: l.AvailableBooks[isbn] + l.BorrowedBooks[isbn],
+                                        err:              fmt.Errorf("Няма наличност на книга %s", isbn),
+                                }
+                        }
+
+                case ReturnBook:
+                        if l.AvailableBooks[isbn]+l.BorrowedBooks[isbn] == 4 {
+                                resChannel <- &TheLibraryResponse{book: l.GetBook(isbn),
+                                        isbn: isbn, availableNumber: l.AvailableBooks[isbn],
+                                        registeredNumber: l.AvailableBooks[isbn] + l.BorrowedBooks[isbn],
+                                        err:              fmt.Errorf("Всички копия са налични %s", isbn),
+                                }
+                        } else {
+                                l.AvailableBooks[isbn]++
+                                l.BorrowedBooks[isbn]--
+                                resChannel <- &TheLibraryResponse{book: l.GetBook(isbn),
+                                        isbn: isbn, availableNumber: l.AvailableBooks[isbn],
+                                        registeredNumber: l.AvailableBooks[isbn] + l.BorrowedBooks[isbn],
+                                        err:              nil,
+                                }
+                        }
+                case CheckAvailability:
+                        resChannel <- &TheLibraryResponse{book: l.GetBook(isbn),
+                                isbn: isbn, availableNumber: l.AvailableBooks[isbn],
+                                registeredNumber: l.AvailableBooks[isbn] + l.BorrowedBooks[isbn],
+                                err:              nil,
+                        }
+                }
+        }
+}
+
+func NewLibrary(librarians int) Library {
+        var books []*Book
+        return TheLibrary{librarians: librarians, books: &books, BorrowedBooks: make(map[string]int), AvailableBooks: make(map[string]int)}
+}
+
+func main() {
+        library := NewLibrary(5)
+        for i := 0; i < 5; i++ {
+                library.AddBookXML([]byte(`
+<book isbn="0954540018">
+<title>Who said the race is Over?</title>
+<author>
+<first_name>Anno</first_name>
+<last_name>Birkin</last_name>
+</author>
+<genre>poetry</genre>
+<pages>80</pages>
+<ratings>
+<rating>5</rating>
+<rating>4</rating>
+<rating>4</rating>
+<rating>5</rating>
+<rating>3</rating>
+</ratings>
+</book>
+`))
+        }
+
+        requests, responses := library.Hello()
+
+        go func() {
+                requests <- TheLibraryRequest{Type: 1, Isbn: "0954540018"}
+        }()
+        response := <-responses
+        a, b := response.GetAvailability()
+        fmt.Printf("A: %d, B: %d\n", a, b)
+}
