func (sap ShopLogInMessageProcessor) ProcessMessage(in *s.InPkg) *s.MessageResult {
	command := *in.Message.Commands
	user, password := _get_user_and_password(command[0].Form.Fields)
	if user == "" || password == "" {
		return s.ErrorMessageResult(errors.New("Не могу извлечь логин и (или) пароль"), &NOT_AUTH_COMMANDS)
	}

	check, err := sap.Users.CheckUserPassword(user, password)
	if err != nil && err != mgo.ErrNotFound {
		return s.ErrorMessageResult(err, &NOT_AUTH_COMMANDS)
	}

	var body string
	var commands []s.OutCommand

	if check {
		sap.Users.SetUserState(in.From, SHOP_STATE_KEY, d.LOGIN)
		body = "Добро пожаловать в интернет магазин Desprice Markt!"
		commands = AUTH_COMMANDS
	} else {
		body = "Не правильные логин или пароль :("
		commands = NOT_AUTH_COMMANDS
	}
	return &s.MessageResult{Body: body, Commands: &commands, Type: "chat"}

}
func (fp *TaxiFeedbackProcessor) ProcessMessage(in *s.InPkg) *s.MessageResult {
	if !fp.API.IsConnected() {
		fp.API.Connect()
		return CONNECTION_ERROR
	}

	commands := *in.Message.Commands
	fdbk, rate := _get_feedback(commands[0].Form.Fields)
	phone, err := _get_phone(in)
	if phone == nil {
		user, _ := fp.Users.GetUserById(in.From)
		if user == nil {
			log.Printf("Error at implying user by id %v", in.From)
			return s.ErrorMessageResult(errors.New("Не могу определить пользователя"), fp.context.Commands[CMDS_FEEDBACK])
		} else {
			phone = &(user.Phone)
		}
	}

	order_id, err := fp.Orders.SetFeedback(in.From, ORDER_PAYED, fdbk, fp.context.Name)
	if err != nil {
		return s.ErrorMessageResult(err, fp.context.Commands[CMDS_NOT_CREATED_ORDER])
	}
	if order_id != nil {
		f := Feedback{IdOrder: *order_id, Rating: rate, FeedBackText: fdbk, Phone: *phone}
		fp.API.Feedback(f)
		result_commands, err := form_commands(in.From, fp.MainDb, fp.context)
		if err != nil {
			return s.ErrorMessageResult(err, fp.context.Commands[CMDS_NOT_CREATED_ORDER])
		}
		return &s.MessageResult{Body: "Спасибо! Ваш отзыв очень важен для нас:)", Commands: result_commands, Type: "chat"}
	} else {
		return &s.MessageResult{Body: "Оплаченный заказ не найден :( Отзывы могут быть только для оплаченных заказов", Commands: fp.context.Commands[CMDS_NOT_CREATED_ORDER], Type: "chat"}
	}
}
func (cop *TaxiCancelOrderProcessor) ProcessMessage(in *s.InPkg) *s.MessageResult {
	if !cop.API.IsConnected() {
		cop.API.Connect()
		return CONNECTION_ERROR
	}
	order_wrapper, err := cop.Orders.GetByOwnerLast(in.From, cop.context.Name)
	if err != nil {
		return s.ErrorMessageResult(err, cop.context.Commands[CMDS_NOT_CREATED_ORDER])
	}
	if order_wrapper == nil || order_wrapper.Active == false {
		return s.ErrorMessageResult(errors.New("У вас нет активных заказов! :("), cop.context.Commands[CMDS_NOT_CREATED_ORDER])
	}

	is_success, message, err := cop.API.CancelOrder(order_wrapper.OrderId)
	if err == nil {
		cop.Orders.SetState(order_wrapper.OrderId, cop.context.Name, ORDER_CANCELED, nil)
		cop.Orders.SetActive(order_wrapper.OrderId, order_wrapper.Source, false)
	}

	if is_success {
		return &s.MessageResult{Body: "Ваш заказ отменен!", Commands: cop.context.Commands[CMDS_NOT_CREATED_ORDER], Type: "chat"}
	} else {
		return &s.MessageResult{Body: fmt.Sprintf("Проблемы с отменой заказа. %v\nЗвони скорее: %+v ", message, cop.alert_phone), Commands: cop.context.Commands[CMDS_NOT_CREATED_ORDER], Type: "chat"}
	}

	commands, err := form_commands(in.From, cop.MainDb, cop.context)
	if err != nil {
		return s.ErrorMessageResult(err, cop.context.Commands[CMDS_NOT_CREATED_ORDER])
	}
	return &s.MessageResult{Body: "У вас нет активных заказов!", Commands: commands}
}
func (cp *TaxiCarPositionMessageProcessor) ProcessMessage(in *s.InPkg) *s.MessageResult {
	if !cp.API.IsConnected() {
		cp.API.Connect()
		return CONNECTION_ERROR
	}
	order_wrapper, err := cp.Orders.GetByOwner(in.From, cp.context.Name, true)
	if err != nil {
		return s.ErrorMessageResult(err, cp.context.Commands[CMDS_NOT_CREATED_ORDER])
	}

	if order_wrapper != nil && !IsOrderNotActual(order_wrapper.OrderState) {
		car_id_ := order_wrapper.OrderData.Get("IDCar")
		if car_id_ == nil {
			return &s.MessageResult{Body: "Не найден идентификатор автомобиля у вашего заказа (видимо, автомобиль вам еще не назначили) :("}
		}
		car_id, ok := car_id_.(int64)
		if !ok {
			return &s.MessageResult{Body: fmt.Sprintf("Не понятен идентификатор автомобиля у вашего заказа :( %#v, %T", car_id_, car_id_)}
		}
		car_info := cp.Cars.GetCarInfo(car_id)
		if car_info != nil {
			return &s.MessageResult{Body: fmt.Sprintf("Lat:%v;Lon:%v", car_info.Lat, car_info.Lon)}
		} else {
			return s.ErrorMessageResult(errors.New("Неизвестный автомобиль."), cp.context.Commands[CMDS_CREATED_ORDER])
		}

	}
	commands, err := form_commands(in.From, cp.MainDb, cp.context)
	if err != nil {
		return s.ErrorMessageResult(err, cp.context.Commands[CMDS_NOT_CREATED_ORDER])
	}
	return &s.MessageResult{Body: "У вас нет активных заказов!", Commands: commands}
}
func (lop ShopLogOutMessageProcessor) ProcessMessage(in *s.InPkg) *s.MessageResult {
	err := lop.Users.SetUserState(in.From, SHOP_STATE_KEY, d.LOGOUT)
	if err != nil && err != mgo.ErrNotFound {
		return s.ErrorMessageResult(err, &NOT_AUTH_COMMANDS)
	}
	return &s.MessageResult{Body: "До свидания! ", Commands: &NOT_AUTH_COMMANDS, Type: "chat"}
}
func (ftbp *FuncTextBodyProcessor) ProcessMessage(in *s.InPkg) *s.MessageResult {
	commands, err := ftbp.F(in)
	if err != nil {
		return s.ErrorMessageResult(err, commands)
	} else {
		if in.UserData != nil {
			err := ftbp.Storage.Users.StoreUserData(in.From, in.UserData)
			if err != nil {
				return DB_ERROR_RESULT
			}
		}
		if in.Message != nil && in.Message.Body != nil {
			mesageBody := in.Message.Body
			ftbp.Storage.Messages.StoreMessage(in.From, ftbp.MessageRecipientIdentity, *mesageBody, in.Message.ID)
			if ftbp.AnswerText != nil {
				answer := ftbp.AnswerText
				return &s.MessageResult{Body: *answer, Type: "chat", IsDeferred: false, Commands: commands}
			} else {
				return &s.MessageResult{IsDeferred: true, Commands: commands}
			}
		} else {
			return MESSAGE_DATA_ERROR_RESULT
		}
	}
	return GLOBAL_ERROR_RESULT
}
func (twmp *TaxiWhereItMessageProcessor) ProcessMessage(in *s.InPkg) *s.MessageResult {
	if !twmp.API.IsConnected() {
		twmp.API.Connect()
		return CONNECTION_ERROR
	}
	order_wrapper, err := twmp.Orders.GetByOwner(in.From, twmp.context.Name, true)
	if err != nil {
		return s.ErrorMessageResult(err, twmp.context.Commands[CMDS_NOT_CREATED_ORDER])
	}

	if order_wrapper != nil && !IsOrderNotActual(order_wrapper.OrderState) {
		ok, result := twmp.API.WhereIt(order_wrapper.OrderId)
		var text string
		if ok {
			text = fmt.Sprintf("О том что вы не видите машину диспетчер уведомлен\n%s", result)
		} else {
			text = fmt.Sprintf("Ошибка!\n%s", result)
		}
		return &s.MessageResult{Body: text, Type: "chat"}
	}
	return s.ErrorMessageResult(errors.New("Не найден активный заказ"), twmp.context.Commands[CMDS_NOT_CREATED_ORDER])

}
func (cpp *TaxiCalculatePriceProcessor) ProcessMessage(in *s.InPkg) *s.MessageResult {
	if !cpp.API.IsConnected() {
		cpp.API.Connect()
		return CONNECTION_ERROR
	}

	commands := *in.Message.Commands
	order, err := _form_order(commands[0].Form.Fields, cpp.AddressHandler)
	if err != nil {
		return s.ErrorMessageResult(err, cpp.context.Commands[CMDS_NOT_CREATED_ORDER])
	}
	cost_s, _ := cpp.API.CalcOrderCost(*order)
	cost := strconv.Itoa(cost_s)
	return &s.MessageResult{Body: fmt.Sprintf("Стоимость будет всего лишь %v рублей!", cost), Type: "chat"}
}
func (osp ShopOrderStateProcessor) ProcessMessage(in *s.InPkg) *s.MessageResult {
	user_state, err := osp.Users.GetUserMultiplyState(in.From, SHOP_STATE_KEY)
	if err != nil && err != mgo.ErrNotFound {
		return s.ErrorMessageResult(err, &NOT_AUTH_COMMANDS)
	}

	var result string
	var commands []s.OutCommand
	if user_state == d.LOGIN {
		result = fmt.Sprintf("Ваш заказ #%v (%v) %v.", rand.Int31n(10000), __choiceString(order_products[:]), __choiceString(order_states[:]))
		commands = AUTH_COMMANDS
	} else {
		result = "Авторизуйтесь пожалуйста!"
		commands = NOT_AUTH_COMMANDS
	}
	return &s.MessageResult{Body: result, Commands: &commands, Type: "chat"}
}
func (rptp RuPostTrackingProcessor) ProcessMessage(in *s.InPkg) *s.MessageResult {
	commands_ptr := in.Message.Commands
	if commands_ptr != nil {
		commands := *commands_ptr
		for _, command := range commands {
			if command.Action == "tracking" && command.Form.Name == "tracking_form" {
				for _, field := range command.Form.Fields {
					if field.Name == "code" {
						code := field.Data.Value
						result, err := Load(code, rptp.Url)
						if err != nil {
							return s.ErrorMessageResult(err, out_g_commands)
						}
						var text string
						if result.ResponseId < 0 {
							text = fmt.Sprintf("Ошибка в почте № %v (%v), попробуйте как-нибудь по-другому.", result.ResponseId, result.Message)
						} else if result.ResponseId == 0 {
							text = "Нет результатов у такого почтового номера, попробуйте какой-нибудь другой."
						} else {
							var wrtr bytes.Buffer
							err = LETTER_TEMPLATE.ExecuteTemplate(&wrtr, "post_letter", result)
							if err != nil {
								log.Printf("err in execut templatE:%v", err)
							}
							text = wrtr.String()
						}
						mr := s.MessageResult{Commands: out_g_commands, Body: text, Type: "chat"}
						return &mr
					}
				}
			} else {
				log.Printf("RU POST TP WARNING: i have command with verififcatio fail: %+v \n with form: %+v", command, command.Form)
			}

		}
	}
	return nil
}
func (nop *TaxiNewOrderProcessor) ProcessMessage(in *s.InPkg) *s.MessageResult {
	log.Printf("check connect")
	if !nop.API.IsConnected() {
		nop.API.Connect()
		return CONNECTION_ERROR
	}
	order_wrapper, err := nop.Orders.GetByOwnerLast(in.From, nop.context.Name)
	if err != nil {
		return s.ErrorMessageResult(err, nop.context.Commands[CMDS_NOT_CREATED_ORDER])
	}

	if order_wrapper == nil || order_wrapper.Active == false {
		commands := *in.Message.Commands
		phone, err := _get_phone(in)
		if err != nil {
			uwrpr, _ := nop.Users.GetUserById(in.From)
			if uwrpr == nil {
				return s.ErrorMessageResult(errors.New("Не предоставлен номер телефона"), nop.context.Commands[CMDS_NOT_CREATED_ORDER])
			} else {
				phone = &(uwrpr.Phone)
			}
		}
		log.Printf("forming order")
		new_order, err := _form_order(commands[0].Form.Fields, nop.AddressHandler)
		if err != nil {
			if _, ok := err.(*AddressNotHere); ok {
				return &s.MessageResult{
					Body:     "Адрес не поддерживается этим такси.",
					Commands: nop.context.Commands[CMDS_NOT_CREATED_ORDER],
					Type:     "chat",
				}
			} else {
				return s.ErrorMessageResult(
					errors.New(fmt.Sprintf("Не могу определить адрес, потому что %v", err.Error())),
					nop.context.Commands[CMDS_NOT_CREATED_ORDER])
			}
		}
		new_order.Phone = *phone
		if mrkps, ok := nop.context.Settings["markups"]; ok {
			markups, ok := mrkps.([]string)
			if ok {
				new_order.Markups = markups
			}
		}

		new_order = ApplyTransforms(new_order, nop.Config.Api.Transformations)
		log.Printf("sending order")
		ans := nop.API.NewOrder(*new_order)
		if !ans.IsSuccess {
			nop.Errors.StoreError(in.From, ans.Message)
			return s.ErrorMessageResult(errors.New(ans.Message), nop.context.Commands[CMDS_NOT_CREATED_ORDER])
		}
		log.Printf("Order was created! %+v \n with content: %+v", ans, ans.Content)

		err = nop.Orders.AddOrderObject(d.OrderWrapper{OrderState: ORDER_CREATED, Whom: in.From, OrderId: ans.Content.Id, Source: nop.context.Name})
		err = nop.Orders.SetActive(ans.Content.Id, nop.context.Name, true)
		if err != nil {
			ok, message, _ := nop.API.CancelOrder(ans.Content.Id)
			log.Printf("Error at persist order. Cancelling order at external api with result: %v, %v", ok, message)
			return s.ErrorMessageResult(err, nop.context.Commands[CMDS_NOT_CREATED_ORDER])
		}
		text := ""

		not_send_price := false

		if nsp_, ok := nop.context.Settings["not_send_price"]; ok {
			if _nsp, ok := nsp_.(bool); ok {
				not_send_price = _nsp
			}
		}
		if not_send_price {
			text = fmt.Sprintf("Ваш заказ создан! %v", NEW_ORDER_TEXT_INFO)
		} else {
			log.Printf("calculate price")
			cost, _ := nop.API.CalcOrderCost(*new_order)
			if cost == 0 {
				log.Printf("Order %v, %v with ZERO cost", nop.context.Name, new_order)
			}
			//retrieving markup information
			var markup_text string
			if len(new_order.Markups) == 1 {
				markups := nop.API.Markups()
				for _, mkrp := range markups {
					markup_id, _ := strconv.ParseInt(new_order.Markups[0], 10, 64)
					if mkrp.ID == markup_id {
						markup_text = mkrp.Name
						break
					}
				}
				text = fmt.Sprintf("Ваш заказ создан! Стоимость поездки составит %v рублей. %s. %v", cost, markup_text, NEW_ORDER_TEXT_INFO)

			} else {
				text = fmt.Sprintf("Ваш заказ создан! Стоимость поездки составит %v рублей. %v", cost, NEW_ORDER_TEXT_INFO)
			}

		}
		return &s.MessageResult{Body: text, Commands: nop.context.Commands[CMDS_CREATED_ORDER], Type: "chat"}
	}
	order_state, _ := InfinityStatusesName[order_wrapper.OrderState]
	return &s.MessageResult{Body: fmt.Sprintf("Заказ уже создан! Потому что в состоянии %v", order_state), Commands: nop.context.Commands[CMDS_NOT_CREATED_ORDER], Type: "chat"}
}
	m "msngr"
	c "msngr/configuration"
	d "msngr/db"
	s "msngr/structs"
	u "msngr/utils"
	"reflect"
	"regexp"
)

const (
	CAR_INFO_UPDATE_TIME = 30.0
	NEW_ORDER_TEXT_INFO  = "В течении 5 минут Вам будет назначен автомобиль. Или перезвонит оператор если ожидаемое время подачи составит более 15 минут."
)

var CONNECTION_ERROR = s.ErrorMessageResult(errors.New("Система обработки заказов такси не отвечает, попробуйте позже."), nil)

type CarInfoProvider struct {
	Cache      *CarsCache
	LastUpdate time.Time
}

func NewCarInfoProvider(cache *CarsCache) *CarInfoProvider {
	return &CarInfoProvider{Cache: cache, LastUpdate: time.Now()}
}

func (cip *CarInfoProvider) GetCarInfo(car_id int64) *CarInfo {
	if time.Now().Sub(cip.LastUpdate).Seconds() > CAR_INFO_UPDATE_TIME {
		cip.Cache.Reload()
		cip.LastUpdate = time.Now()
	}
func (odp *OrderBakeProcessor) ProcessMessage(in *s.InPkg) *s.MessageResult {
	if in.UserData != nil && in.Message != nil && in.Message.Commands != nil {
		err := odp.Storage.Users.StoreUserData(in.From, in.UserData)
		if err != nil {
			return m.DB_ERROR_RESULT
		}
		commands := *(in.Message.Commands)
		for _, command := range commands {
			if command.Action == "order_bake" && command.Form.Name == "order_bake_form" {
				order, err := NewCoffeeOrderFromForm(command.Form)
				if err != nil {
					log.Printf("COFFEE BOT error at forming order from form: %v", err)
					return m.MESSAGE_DATA_ERROR_RESULT
				}
				orderId := u.GenIntId()
				err = odp.Storage.Orders.AddOrderObject(db.OrderWrapper{
					OrderId:   orderId,
					When:      time.Now(),
					Whom:      in.From,
					Source:    odp.CompanyName,
					Active:    true,
					OrderData: order.ToOrderData(),
				})
				if err != nil {
					log.Printf("CB Error at storing bake order %v", err)
					return m.DB_ERROR_RESULT
				}
				err = odp.Storage.Messages.StoreMessageObject(db.MessageWrapper{
					MessageID:         in.Message.ID,
					From:              in.From,
					To:                odp.CompanyName,
					Body:              "Заказ выпечки!",
					Unread:            1,
					NotAnswered:       1,
					Time:              time.Now(),
					TimeStamp:         time.Now().Unix(),
					TimeFormatted:     time.Now().Format(time.Stamp),
					Attributes:        []string{"coffee"},
					AdditionalData:    order.ToAdditionalMessageData(),
					AdditionalFuncs:   getAdditionalFuncs(orderId, odp.CompanyName, in.From, in.GetMessageId()),
					RelatedOrderState: "Отправлено в кофейню",
					RelatedOrder:      orderId,
				})
				if err != nil {
					log.Printf("CB Error at storing bake message %v", err)
					return m.DB_ERROR_RESULT
				}
				cmds, err := odp.CommandsFunc(in)
				if err != nil {
					return s.ErrorMessageResult(err, cmds)
				}
				return &s.MessageResult{
					Commands: cmds,
					Type:     "chat",
					Body:     "Ваш заказ создан!",
				}
			}

		}
	}
	return m.MESSAGE_DATA_ERROR_RESULT
}