Ралица обнови решението на 06.12.2015 17:58 (преди над 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 DogeLibrarySizeError struct {
+        isbn string
+}
+
+func (d DogeLibrarySizeError) Error() string {
+        return "Има 4 копия на книга " + d.isbn
+}
+
+type AuthorType struct {
+        First_name string `xml:"first_name"`
+        Last_name  string `xml:"last_name"`
+}
+
+type Book struct {
+        XMLName xml.Name   `xml:"book"`
+        Isbn    string     `xml:"isbn,attr"`
+        Title   string     `xml:"title"`
+        Author  AuthorType `xml:"author"`
+        Ratings []int      `xml:"ratings>rating"`
+        Pages   int        `xml:"pages"`
+        Genre   string     `xml:"genre"`
+}
+
+func (b Book) String() string {
+        var (
+                isbn              = b.Isbn
+                title             = b.Title
+                firstNameOfAuthor = b.Author.First_name
+                lastNameOfAuthor  = b.Author.Last_name
+        )
+
+        return "[" + isbn + "] " + title + " от " + firstNameOfAuthor + " " + lastNameOfAuthor
+}
+
+type BookItem struct {
+        book       *Book
+        count      int
+        registered int
+}
+
+type DogeLibrary struct {
+        books      map[string]*BookItem
+        librarians int
+        sem        chan struct{}
+        mutex      sync.RWMutex
+}
+
+func (d *DogeLibrary) AddBookJSON(data []byte) (int, error) {
+        var (
+                book           Book
+                unmarshalError error
+        )
+
+        unmarshalError = json.Unmarshal(data, &book)
+        if unmarshalError != nil {
+                panic(fmt.Sprintf("%v", unmarshalError))
+        }
+
+        var (
+                copiesCount = d.getAvailable(book.Isbn)
+                sizeError   *DogeLibrarySizeError
+        )
+
+        if copiesCount >= 4 {
+                sizeError = &DogeLibrarySizeError{isbn: book.Isbn}
+        } else {
+                d.addBook(book)
+        }
+
+        return copiesCount, sizeError
+}
+
+func (d *DogeLibrary) AddBookXML(data []byte) (int, error) {
+        var (
+                book           Book
+                unmarshalError error
+        )
+
+        unmarshalError = xml.Unmarshal(data, &book)
+        if unmarshalError != nil {
+                panic(fmt.Sprintf("%v", unmarshalError))
+        }
+
+        var (
+                copiesCount = d.getAvailable(book.Isbn)
+                sizeError   *DogeLibrarySizeError
+        )
+
+        if copiesCount >= 4 {
+                sizeError = &DogeLibrarySizeError{isbn: book.Isbn}
+        } else {
+                d.addBook(book)
+        }
+
+        return copiesCount, sizeError
+}
+
+func NewLibrary(librarians int) Library {
+
+        var d = new(DogeLibrary)
+        d.books = make(map[string]*BookItem)
+        d.librarians = librarians
+        d.sem = make(chan struct{}, d.librarians)
+
+        for i := 0; i < d.librarians; i++ {
+                d.sem <- struct{}{}
+        }
+
+        return d
+}
+
+func (d *DogeLibrary) getAvailable(isbn string) int {
+        if d.exists(isbn) {
+                var bookItem = d.books[isbn]
+                return bookItem.count
+        } else {
+                return 0
+        }
+}
+
+func (d *DogeLibrary) getRegistered(isbn string) int {
+        if d.exists(isbn) {
+                var bookItem = d.books[isbn]
+                return bookItem.registered
+        } else {
+                return 0
+        }
+}
+
+func (d *DogeLibrary) exists(isbn string) bool {
+        var _, exists = d.books[isbn]
+        return exists
+}
+
+func (d *DogeLibrary) addBook(b Book) bool {
+        if d.exists(b.Isbn) {
+                var bookItem = d.books[b.Isbn]
+                if bookItem.registered+1 > 4 {
+                        return false
+                } else {
+                        bookItem.count++
+                        bookItem.registered++
+                }
+        } else {
+                d.books[b.Isbn] = &BookItem{book: &b, count: 1, registered: 1}
+        }
+
+        return true
+}
+
+func (d *DogeLibrary) removeBook(isbn string) (*Book, bool) {
+        if d.exists(isbn) {
+                var bookItem = d.books[isbn]
+                bookItem.count--
+                return bookItem.book, true
+        } else {
+                return nil, false
+        }
+}
+
+type ErrorUnknownBook struct {
+        message string
+}
+
+func (e *ErrorUnknownBook) Error() string {
+        return e.message
+}
+
+func (d *DogeLibrary) Hello() (chan<- LibraryRequest, <-chan LibraryResponse) {
+
+        <-d.sem
+
+        var libraryRequestChannel = make(chan LibraryRequest)
+        var libraryResponseChannel = make(chan LibraryResponse, 1)
+
+        go func() {
+                for request := range libraryRequestChannel {
+
+                        var requestType = request.GetType()
+                        var isbn = request.GetISBN()
+
+                        var response = new(DogeLibraryResponse)
+
+                        d.mutex.Lock()
+                        if d.exists(isbn) {
+                                response.registered = d.getRegistered(isbn)
+                                response.available = d.getAvailable(isbn)
+                                response.error = nil
+                        } else {
+                                response.registered = 0
+                                response.available = 0
+                                response.error = &ErrorUnknownBook{message: "Непозната книга " + isbn}
+                        }
+
+                        if requestType == 1 {
+                                var book, _ = d.removeBook(isbn)
+                                response.book = book
+                        } else if requestType == 2 {
+                                //~ d.returnBook(isbn)
+                                response.book = nil
+                        } else if requestType == 3 {
+                                //
+                        }
+
+                        d.mutex.Unlock()
+
+                        libraryResponseChannel <- response
+                }
+
+                d.sem <- struct{}{}
+        }()
+
+        return libraryRequestChannel, libraryResponseChannel
+}
+
+type DogeLibraryResponse struct {
+        registered int
+        available  int
+        book       *Book
+        error      error
+}
+
+func (d *DogeLibraryResponse) GetBook() (fmt.Stringer, error) {
+        return d.book, d.error
+}
+
+func (d *DogeLibraryResponse) GetAvailability() (available int, registered int) {
+        return d.available, d.registered
+}
+
+func Dump(d *DogeLibrary) {
+        for _, book := range d.books {
+                fmt.Println(book)
+        }
+}
+
+func main() {
+        var json = []byte(`{
+                "isbn": "0954540018",
+                "title": "Who Said the Race is Over?",
+                "author": {
+                        "first_name": "Anno",
+                        "last_name": "Birkin"
+                },
+                "genre": "poetry",
+                "pages": 80,
+                "ratings": [5, 4, 4, 5, 3]
+        }`)
+
+        var xml = []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>
+        `)
+
+        var lib = NewLibrary(16)
+
+        lib.AddBookJSON(json)
+        lib.AddBookXML(xml)
+
+        Dump(lib.(*DogeLibrary))
+}
