func process_message_pkg(buff *s.OutPkg, in *s.InPkg, context *BotContext) (*s.OutPkg, bool, error) {
	var err error
	var isDeferred bool

	if in.Message.Type == "error" {
		log.Printf("error because type of message is error:\n %+v", in.Message.Error)
		return buff, false, errors.New(fmt.Sprintf("Error because type of message id: %+v is error", in.Message.ID))
	}

	in_commands := in.Message.Commands
	for _, command := range *in_commands {
		action := command.Action
		if commandProcessor, ok := context.MessageProcessors[action]; ok {
			log.Printf("BOT found [%v] action", action)
			buff, isDeferred, err = process_message(commandProcessor, buff, in)
		} else {
			err = errors.New("Команда не поддерживается.")
			buff.Message = &s.OutMessage{
				Thread: in.Message.Thread,
				ID:     u.GenStringId(),
				Type:   "chat",
				Body:   err.Error(),
			}
		}
	}
	return buff, isDeferred, err
}
func process_request_pkg(buff *s.OutPkg, in *s.InPkg, context *BotContext) (*s.OutPkg, error) {
	if in.Request.Type == "error" {
		log.Printf("error because type of request is error:\n %+v", in.Request)
		return buff, errors.New("error because request type is error")
	}
	action := in.Request.Query.Action
	buff.Request = &s.OutRequest{ID: u.GenStringId(), Type: "result"}
	buff.Request.Query.Action = action
	buff.Request.Type = "result"

	if commandProcessor, ok := context.RequestProcessors[action]; ok {
		requestResult := commandProcessor.ProcessRequest(in)
		if requestResult.Error != nil {
			err := requestResult.Error
			return buff, err
		} else {
			//normal our request forming
			buff.Request.Query.Result = *requestResult.Commands
			if requestResult.Type != "" {
				buff.Request.Type = requestResult.Type
			}
		}
	} else {
		err := errors.New("Команда не поддерживается.")
		return buff, err
	}
	return buff, nil
}
func send_key(key string, userData *s.InUserData) string {
	out := s.InPkg{UserData: userData, Message: &s.InMessage{Type: "chat", ID: utils.GenStringId(), Thread: utils.GenStringId(), Body: &key}, From: userData.Name}
	in, err := test.POST(address, &out)
	if err != nil {
		log.Printf("Error: %v", err)
		return ""
	}
	return strings.TrimSpace(in.Message.Body)
}
func notify_cancel_order(taxiContext *TaxiContext, botContext *m.BotContext, db_order *d.OrderWrapper) {
	taxiContext.Notifier.Notify(s.OutPkg{
		To: db_order.Whom,
		Message: &s.OutMessage{
			ID:       u.GenStringId(),
			Type:     "chat",
			Body:     "Ваш заказ отменен!",
			Commands: botContext.Commands["commands_at_not_created_order"],
		},
	})
}
func sendNewOrder(from, to string) {
	street_from := get_street(from, "street_from")
	house_from := s.InField{Data: s.InFieldData{Value: "1"}, Type: "text", Name: "house_from"}

	street_to := get_street(to, "street_to")
	house_to := s.InField{Data: s.InFieldData{Value: "1"}, Type: "text", Name: "house_from"}
	entrance := s.InField{Type: "number", Name: "entrance"}

	form := s.InForm{Fields: []s.InField{street_from, street_to, house_from, house_to, entrance}}
	command := s.InCommand{Action: "new_order", Form: form}

	out := s.InPkg{
		UserData: &userData,
		Message:  &s.InMessage{Type: "chat", ID: utils.GenStringId(), Thread: utils.GenStringId(), Commands: &[]s.InCommand{command}},
		From:     userData.Name,
	}

	in, err := test.POST(address, &out)
	log.Printf("RESULT: %s\nerr?:%v", in.Message.Body, err)
}
func FormNotification(context *TaxiContext, ow *d.OrderWrapper, previous_state int, car_info CarInfo, deliv_time time.Time) *s.OutPkg {
	var text string
	switch ow.OrderState {
	case ORDER_ASSIGNED:
		if previous_state != ORDER_ASSIGNED {
			text = fmt.Sprintf("%v %v, время подачи %v.", nominated, car_info, deliv_time.Format("15:04"))
		}
	case ORDER_CAR_SET_OUT:
		if previous_state != ORDER_CAR_SET_OUT {
			if previous_state != ORDER_ASSIGNED {
				text = fmt.Sprintf("%v %v. %v, время подачи %v", nominated, car_info, car_set_out, deliv_time.Format("15:04"))
			} else {
				text = fmt.Sprintf("%v, время подачи %v", car_set_out, deliv_time.Format("15:04"))
			}
		}

	case ORDER_CLIENT_WAIT:
		if previous_state == ORDER_CREATED {
			text = fmt.Sprintf("%v %v %v %v.", car_arrived, good_passage, nominated, car_info)
		} else {
			text = fmt.Sprintf("%v %v", car_arrived, good_passage)
		}
	case ORDER_IN_PROCESS:
		if u.In(previous_state, []int{ORDER_CLIENT_WAIT, ORDER_DOWNTIME}) {
			return nil
		} else if previous_state == ORDER_CREATED {
			text = fmt.Sprintf("%v %v %v %v.", car_arrived, good_passage, nominated, car_info)
		} else {
			text = fmt.Sprintf("%v %v", car_arrived, good_passage)
		}
	case ORDER_PAYED:
		text = order_end
		context.DataBase.Orders.SetActive(ow.OrderId, ow.Source, false)

	case ORDER_CANCELED:
		if !u.In(previous_state, []int{ORDER_PAYED, ORDER_NOT_PAYED}) {
			text = order_end
		} else {
			text = order_canceled
		}
		context.DataBase.Orders.SetActive(ow.OrderId, ow.Source, false)
	}

	if text != "" {
		out := s.OutPkg{To: ow.Whom, Message: &s.OutMessage{ID: u.GenStringId(), Type: "chat", Body: text}}
		return &out
	}
	return nil
}
func process_message(commandProcessor s.MessageCommandProcessor, buff *s.OutPkg, in *s.InPkg) (*s.OutPkg, bool, error) {
	messageResult := commandProcessor.ProcessMessage(in)
	buff.Message = &s.OutMessage{
		Thread: in.Message.Thread,
		ID:     u.GenStringId(),
		Type:   "chat",
	}
	if messageResult.Type != "" {
		buff.Message.Type = messageResult.Type
	}
	buff.Message.Body = messageResult.Body
	buff.Message.Commands = messageResult.Commands

	log.Printf("message result\ntype: %+v \nbody:%+v\ncommands:%+v\ndeffered?: %+v", messageResult.Type, buff.Message.Body, buff.Message.Commands, messageResult.IsDeferred)

	return buff, messageResult.IsDeferred, messageResult.Error
}
func FormBotController(context *BotContext, db *db.MainDb) controllerHandler {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.Method != "POST" {
			http.Error(w, "I can not work with non POST methods", 405)
			return
		}
		log.Printf("have requests %+v", r)
		out := &s.OutPkg{}
		var in *s.InPkg
		var isError, isDeferred bool
		var global_error, request_error, message_error error

		check := context.Check
		if check != nil {
			if detail, ok := check(); !ok {
				out.Message = &s.OutMessage{Type: "chat", Thread: "0", ID: u.GenStringId(), Body: fmt.Sprintln(detail)}
				PutOutPackage(w, out, true, false)
				return
			}
		}

		in, global_error = FormInPackage(r)
		if in != nil {
			out.To = in.From
			if in.Request != nil {
				out, request_error = process_request_pkg(out, in, context)
			}
			if in.Message != nil {
				storedMessage, _ := db.Messages.GetMessageByMessageId(in.Message.ID)
				log.Printf("BOT in message id %v", in.Message.ID)
				if storedMessage != nil {
					log.Printf("BOT: Have duplicate message. Will be quiet ignoring it...")
					return
				}
				if in.Message.Error != nil {
					if val, ok := ERRORS_MAP[in.Message.Error.Condition]; ok {
						_, err_type := val()
						log.Printf("BOT: Here is error %v %v. For message id %v", in.Message.Error.Code, err_type, in.Message.ID)
						db.Messages.UpdateMessageStatus(in.Message.ID, err_type, in.Message.Error.Condition)
					} else {
						log.Printf("BOT: Error not in my errors map %v", in.Message.Error.Condition)
						db.Messages.UpdateMessageStatus(in.Message.ID, in.Message.Error.Type, in.Message.Error.Condition)
					}
					return
				}
				if in.Message.Commands == nil {
					if non_commands_processor, ok := context.MessageProcessors[""]; ok {
						out, isDeferred, message_error = process_message(non_commands_processor, out, in)
					} else {
						log.Printf("warn will sended message without commands: %+v\n from %v (userdata: %+v)", in.Message, in.From, in.UserData)
					}
				} else {
					out, isDeferred, message_error = process_message_pkg(out, in, context)
				}
			}
			if in.Message == nil && in.Request == nil {
				global_error = errors.New("Ничего не понятно!")
			}
		}

		if DEBUG {
			log.Printf("package processed!\nrequest:%+v\nmessage:%+v\nmessage\nrequest_error: %+v, message error: %+v", out.Request, out.Message, request_error, message_error)
		}

		if message_error != nil {
			out = &s.OutPkg{}
			out.Message = &s.OutMessage{Type: "error", Thread: "0", ID: u.GenStringId(), Body: fmt.Sprintf("%+v", message_error)}
			isError = true
		} else if global_error != nil {
			out = &s.OutPkg{}
			out.Message = &s.OutMessage{Type: "error", Thread: "0", ID: u.GenStringId(), Body: fmt.Sprintf("%+v", global_error)}
			isError = true
		} else if request_error != nil {
			out = &s.OutPkg{}
			out.Request = &s.OutRequest{Type: "error", ID: u.GenStringId()}
			out.Request.Query.Text = fmt.Sprintf("%+v", request_error)
			isError = true
		}

		PutOutPackage(w, out, isError, isDeferred)
	}

}
func TestTaxiInfinityFail(t *testing.T) {
	conf := c.ReadTestConfigInRecursive()
	db := d.NewMainDb(conf.Main.Database.ConnString, conf.Main.Database.Name)
	taxi_conf := conf.Taxis["fake"]

	t.Logf("taxi api configuration for %+v:\n%v", taxi_conf.Name, taxi_conf.Api)
	external := i.GetTestInfAPI(taxi_conf.Api)

	external_api := external.(taxi.TaxiInterface)
	external_address_supplier := external.(taxi.AddressSupplier)

	apiMixin := taxi.ExternalApiMixin{API: external_api}

	carsCache := taxi.NewCarsCache(external_api)
	notifier := n.NewNotifier(conf.Main.CallbackAddr, taxi_conf.Chat.Key, db)

	address_handler, address_supplier := GetAddressInstruments(conf, taxi_conf.Name, external_address_supplier)
	configStore := d.NewConfigurationStorage(conf.Main.ConfigDatabase)
	botContext := taxi.FormTaxiBotContext(&apiMixin, db, configStore, taxi_conf, address_handler, carsCache)
	controller := m.FormBotController(botContext, db)

	t.Logf("Was create bot context: %+v\n", botContext)
	http.HandleFunc(fmt.Sprintf("/taxi/%v", taxi_conf.Name), controller)

	go func() {
		taxiContext := taxi.TaxiContext{API: external_api, DataBase: db, Cars: carsCache, Notifier: notifier}
		t.Logf("Will start order watcher for [%v]", botContext.Name)
		taxi.TaxiOrderWatch(&taxiContext, botContext)
	}()

	http.HandleFunc(fmt.Sprintf("/taxi/%v/streets", taxi_conf.Name), func(w http.ResponseWriter, r *http.Request) {
		geo.StreetsSearchController(w, r, address_supplier)
	})

	go func() {
		server_address := fmt.Sprintf(":%v", conf.Main.Port)
		t.Logf("\nStart listen and serving at: %v\n", server_address)
		server := &http.Server{
			Addr: server_address,
		}
		server.ListenAndServe()
	}()

	u.After(external_api.IsConnected, func() {
		inf_api := external.(*i.InfinityAPI)
		for i, _ := range inf_api.ConnStrings {
			inf_api.ConnStrings[i] += "w"
		}
	})

	_, err := u.GET(taxi_conf.DictUrl, &map[string]string{"q": "лесос"})
	if err != nil {
		t.Error("Error at getting street %v", err)
	}

	out_res, err := tu.POST(fmt.Sprintf("http://localhost:%v/taxi/%v", conf.Main.Port, taxi_conf.Name), &structs.InPkg{
		Message: &structs.InMessage{
			ID: u.GenStringId(),
			Commands: &[]structs.InCommand{
				structs.InCommand{Action: "information", Title: "information"},
			},
		},
		From:     "test user",
		UserData: &structs.InUserData{Name: "TEST"},
	})

	if err != nil {
		t.Errorf("Error at unmarshal result info %v", err)
	}

	if out_res == nil {
		t.Error("Out info result is nil!")
	} else {
		if out_res.Message.Type != "chat" {
			t.Errorf("Out message type != chat, but == %v", out_res.Message.Type)
		}
		ch, _ := configStore.GetChatConfig(taxi_conf.Chat.CompanyId)

		if out_res.Message.Body != ch.Information {
			t.Errorf("Out message body != info in config, but == %v", out_res.Message.Body)
		}
	}

}
func (n *Notifier) NotifyTextToMembers(text string) (*s.OutPkg, *db.MessageWrapper, error) {
	result := s.OutPkg{Message: &s.OutMessage{ID: utils.GenStringId(), Type: "chat", Body: text}}
	message, err := n.Notify(result)
	return &result, message, err
}
func (n *Notifier) NotifyTextWithCommands(to, text string, commands *[]s.OutCommand) (*s.OutPkg, *db.MessageWrapper, error) {
	result := s.OutPkg{To: to, Message: &s.OutMessage{ID: utils.GenStringId(), Type: "chat", Body: text, Commands: commands}}
	message, err := n.Notify(result)
	return &result, message, err
}