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