net.cbtltd.rest.yandex.A_Handler.java Source code

Java tutorial

Introduction

Here is the source code for net.cbtltd.rest.yandex.A_Handler.java

Source

/**
 * @author   Chirayu Shah, Isaac Mahgrefteh
 * @see      License at http://razorpms.com/razor/License.html
 * @version   2.00
 */
package net.cbtltd.rest.yandex;

import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.security.Security;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.io.PrintWriter;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;

import javax.imageio.ImageIO;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

//import jdk.internal.jfr.events.FileWriteEvent;
import net.cbtltd.rest.GatewayHandler;
import net.cbtltd.rest.GoogleLocationLimitException;
import net.cbtltd.rest.payment.ReservationPrice;
import net.cbtltd.rest.response.QuoteDetail;
import net.cbtltd.server.MonitorService;
import net.cbtltd.server.PartnerHandler;
import net.cbtltd.server.PartnerService;
import net.cbtltd.server.RazorServer;
import net.cbtltd.server.RelationService;
import net.cbtltd.server.ServiceException;
import net.cbtltd.server.TextService;
import net.cbtltd.server.UploadFileService;
import net.cbtltd.server.WebService;
import net.cbtltd.server.api.AlertMapper;
import net.cbtltd.server.api.AttributeMapper;
import net.cbtltd.server.api.LocationMapper;
import net.cbtltd.server.api.PartyMapper;
import net.cbtltd.server.api.PriceMapper;
import net.cbtltd.server.api.ProductMapper;
import net.cbtltd.server.api.ReservationMapper;
import net.cbtltd.server.api.TextMapper;
import net.cbtltd.shared.Currency;
import net.cbtltd.shared.Downloaded;
import net.cbtltd.shared.Error;
import net.cbtltd.shared.Fee;
import net.cbtltd.shared.Image;
import net.cbtltd.shared.Language;
import net.cbtltd.shared.License;
import net.cbtltd.shared.Location;
import net.cbtltd.shared.NameId;
import net.cbtltd.shared.Partner;
import net.cbtltd.shared.Party;
import net.cbtltd.shared.Price;
import net.cbtltd.shared.Price.Rule;
import net.cbtltd.shared.Product;
import net.cbtltd.shared.Relation;
import net.cbtltd.shared.Reservation;
import net.cbtltd.shared.Text;
import net.cbtltd.shared.Time;
import net.cbtltd.shared.Unit;
import net.cbtltd.shared.api.IsPartner;
import net.cbtltd.shared.finance.gateway.CreditCard;
import net.cbtltd.shared.finance.gateway.CreditCardType;
import net.cbtltd.server.api.FeeMapper;
import net.cbtltd.server.api.ImageMapper;

import org.apache.commons.lang3.StringUtils;
import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.DurationFieldType;
import org.xml.sax.InputSource;

import sun.misc.BASE64Encoder;

import com.bookingnet.config.RazorConfig;
import com.bookingnet.utils.CustomHttpConnection;
import com.bookingnet.utils.ISO8859CharacterNormalizer;

/**
 * Class A_Handler manages the Nextpax API
 * ONLY file being used. ALL other files have NO use.
 * FTP server = ftp://secure.nextpax.com
 * FTP username = bookingnet
 * FTP password = FEJvvn$LYGCUd-2_Vq4zI
 * Super-XML sender ID = MYB112 (OLD)
 * New SenderID = FLI112 (updated on Dec. 2, 2014)
 * https://secure.nextpax.com/extranet/index.php
 * The username for the Extranet is "bookingnet" and the password is "BAD5PqtE".
 * 
 * @author cshah issac
 * @version Apr 18, 2014
 */
public class A_Handler extends PartnerHandler implements IsPartner {

    private static final Logger LOG = Logger.getLogger(A_Handler.class.getName());
    private static final DateFormat DF = new SimpleDateFormat("yyyy-MM-dd");
    private static final DateFormat TF = new SimpleDateFormat("hh:mm:ss");
    private static final String IMAGE_URL = "http://secure.nextpax.net/img/";
    private static final String BASE_NEXTPAX_URL = "https://secure.nextpax.com";
    private static final String CANCELLATION_URL = BASE_NEXTPAX_URL + "/comm/bookingnet_cancel_novasol.php?";
    private static final String SENDERID = "FLI112";
    private static final String EMAILCREDITCARD = "\nOnce the transaction is complete, the property manager will contact you for payment information.";
    private static final Pattern PATTERN_FOR_SPECIAL_CHARACTERS = Pattern.compile("[?]");

    private static Document document = null;
    private static Namespace ns = null;

    private static long startTime = 0;
    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    static {
        Security.insertProviderAt(new BouncyCastleProvider(), 1);
    }

    /**
     * Instantiates a new partner handler.
     * 
     * @param sqlSession the current SQL session.
     * @param partner the partner.
     */
    public A_Handler(Partner partner) {
        super(partner);
    }

    /**
     * Gets the connection to the nextpax server and executes the specified request.
     * 
     * @param url the connection URL.
     * @param rq the request object.
     * @return the XML string returned by the message.
     * @throws Throwable the exception thrown by the operation.
     */
    private static final String getConnection(String rq) throws Throwable {
        String xmlString = "";
        CustomHttpConnection connection = new CustomHttpConnection();

        LOG.debug("NEXTPAX is using: " + RazorConfig.getNextPaxRequestURL());
        BASE64Encoder enc = new sun.misc.BASE64Encoder();
        Security.addProvider(new BouncyCastleProvider());
        String userpassword = "bookingnet" + ":" + "BAD5PqtE";
        String encodedAuthorization = enc.encode(userpassword.getBytes());
        xmlString = connection.createPostRequest(RazorConfig.getNextPaxRequestURL(), encodedAuthorization,
                "application/xml", rq);
        return xmlString;
    }

    /**
     * Get unzipped input stream for file name.
     * 
     * @param fn the file name.
     * @return the input stream.
     * @throws Throwable the exception that can be thrown.
     */
    private final synchronized InputStream ftp(String fn) throws Throwable {
        String urlname = "ftp://bookingnet:FEJvvn$LYGCUd-2_Vq4zI@secure.nextpax.com/" + fn + ".gz;type=i";
        URL url = new URL(urlname);
        URLConnection urlc = url.openConnection();

        byte[] buf = new byte[1024];
        GZIPInputStream zinstream = new GZIPInputStream(urlc.getInputStream());
        FileOutputStream outstream = new FileOutputStream(fn);
        int n;
        while ((n = zinstream.read(buf, 0, 1024)) > -1) {
            outstream.write(buf, 0, n);
        }
        outstream.close();
        zinstream.close();
        return new BufferedInputStream(new FileInputStream(fn));
    }

    /**
     * Delete file.
     * 
     * @param fn the file name.
     */
    private static final void delete(String fn) {
        try {
            File file = new File(fn);
            file.delete();
        } catch (Throwable x) {
            LOG.error(x.getMessage());
        }
    }

    /**
     * Returns if the property is available for the reservation.
     * 
     * @param sqlSession the current SQL session.
     * @param reservation the reservation for collisions
     * @return list of collisions
     */
    @Override
    public boolean isAvailable(SqlSession sqlSession, Reservation reservation) {
        StringBuilder sb = new StringBuilder();
        Date now = new Date();
        long time = now.getTime();
        String SenderSessionID = time + "bookingnetS";
        String ReceiverSessionID = time + "bookingnetR";
        String rq;
        String rs = null;
        boolean available = false;
        if (reservation.notActive()) {
            throw new ServiceException(Error.reservation_state,
                    reservation.getId() + " state " + reservation.getState());
        }

        Product product = sqlSession.getMapper(ProductMapper.class).read(reservation.getProductid());
        if (product == null) {
            throw new ServiceException(Error.product_id, reservation.getProductid());
        }
        if (reservation.noAgentid()) {
            throw new ServiceException(Error.reservation_agentid);
        }
        Party agent = sqlSession.getMapper(PartyMapper.class).read(reservation.getAgentid());
        if (agent == null) {
            throw new ServiceException(Error.party_id, reservation.getAgentid());
        }
        if (reservation.noCustomerid()) {
            reservation.setCustomerid(Party.NO_ACTOR);
        }
        Party customer = sqlSession.getMapper(PartyMapper.class).read(reservation.getCustomerid());
        if (customer == null) {
            throw new ServiceException(Error.reservation_customerid, reservation.getCustomerid());
        }

        try {
            sb.append("<?xml version='1.0' ?>");
            sb.append("<TravelMessage VersionID='1.8N'>");
            sb.append(" <Control Language='NL' Test='nee'>");
            sb.append("    <SenderSessionID>" + SenderSessionID + "</SenderSessionID>");
            sb.append("    <ReceiverSessionID>" + ReceiverSessionID + "</ReceiverSessionID>");
            sb.append("    <Date>" + DF.format(new Date()) + "</Date>");
            sb.append("    <Time Reliability='zeker'>" + TF.format(new Date()) + "</Time>");
            sb.append("   <MessageSequence>1</MessageSequence>");
            sb.append("   <SenderID>" + SENDERID + "</SenderID>");
            sb.append("  <ReceiverID>NPS001</ReceiverID>");
            sb.append("   <RequestID>AvailabilitybookingnetRequest</RequestID>");
            sb.append("   <ResponseID>AvailabilitybookingnetResponse</ResponseID>");
            sb.append(" </Control>");
            sb.append("  <TRequest>");
            sb.append("    <AvailabilitybookingnetRequest>");
            sb.append("      <PackageDetails WaitListCheck='ja'>");
            sb.append("          <AccommodationID>" + "A" + product.getAltid() + "</AccommodationID>");
            sb.append("          <ArrivalDate>" + DF.format(reservation.getFromdate()) + "</ArrivalDate>");
            sb.append("        <Duration DurationType='dagen'>" + reservation.getDuration(Time.DAY).intValue()
                    + "</Duration>");
            sb.append("     </PackageDetails>");
            sb.append("   </AvailabilitybookingnetRequest>");
            sb.append("  </TRequest>");
            sb.append("</TravelMessage>");

            rq = sb.toString();
            LOG.debug("isAvailable rq: \n" + rq + "\n");

            rs = getConnection(rq);
            LOG.debug("isAvailable rs: \n" + rs + "\n");

            XPathFactory factory = XPathFactory.newInstance();
            XPath xpath = factory.newXPath();
            InputSource inputSource = new InputSource(new StringReader(rs.toString()));
            Double bookID = (Double) xpath.evaluate("//PackageID", inputSource, XPathConstants.NUMBER);
            available = !bookID.isNaN();
        } catch (Throwable e) {
            LOG.error(e.getMessage());
        }
        return available;
    }

    /**
     * Create reservation.
     * 
     * @param sqlSession the current SQL session.
     * @param reservation the reservation to be created.
     * @param product the product to be reserved.
     */
    @Override
    public void createReservation(SqlSession sqlSession, Reservation reservation) {
        LOG.error("You got into CreateBooking for nextpax");
        Date now = new Date();
        long timestamp = now.getTime();
        String message = "createReservation " + reservation.getId();
        String rq;
        String rs;
        Map<String, String> result = new HashMap<String, String>(); // never used.
        LOG.debug(message);
        LOG.error("Block 1 entry");

        StringBuilder sb = new StringBuilder();
        long time = timestamp;
        String SenderSessionID = time + "bookingnetS";
        String ReceiverSessionID = time + "bookingnetR";
        LOG.error("Block 2 entry");
        try {
            if (reservation.notActive()) {
                throw new ServiceException(Error.reservation_state,
                        reservation.getId() + " state " + reservation.getState());
            }

            Product product = sqlSession.getMapper(ProductMapper.class).read(reservation.getProductid());
            if (product == null) {
                throw new ServiceException(Error.product_id, reservation.getProductid());
            }
            if (reservation.noAgentid()) {
                throw new ServiceException(Error.reservation_agentid);
            }
            LOG.error("Block 3 entry");
            Party agent = sqlSession.getMapper(PartyMapper.class).read(reservation.getAgentid());
            if (agent == null) {
                throw new ServiceException(Error.party_id, reservation.getAgentid());
            }
            if (reservation.noCustomerid()) {
                reservation.setCustomerid(Party.NO_ACTOR);
            }
            Party customer = sqlSession.getMapper(PartyMapper.class).read(reservation.getCustomerid());
            LOG.error("Block 4 entry");
            if (customer == null) {
                throw new ServiceException(Error.reservation_customerid, reservation.getCustomerid());
            }
            Price price = sqlSession.getMapper(PriceMapper.class).altidfromdate(reservation);
            if (price == null || (!price.hasAltid())) {
                throw new ServiceException(Error.price_data, reservation.getCustomerid());
            }

            if (creditCardOnly(Integer.parseInt(product.getAltSupplierId()))) {
                throw new ServiceException(Error.card_notsupported, product.getId() + "NextPax Create Reservation");
            }

            LOG.error("Block 5 entry");
            // sequence SellRequest.xml -> AssignRequest.xml -> BookRequest.xml
            // SellRequest.xml
            sb.append("<?xml version='1.0' ?>");
            sb.append("<TravelMessage VersionID='1.8N'>");
            sb.append("  <Control Language='NL' Test='nee'>");// + getXMLTestAttrubuiteStatus() + "'>");
            sb.append("    <SenderSessionID>" + SenderSessionID + "</SenderSessionID>");
            sb.append("    <ReceiverSessionID>" + ReceiverSessionID + "</ReceiverSessionID>");
            sb.append("    <Date>" + DF.format(new Date()) + "</Date>");
            sb.append("    <Time Reliability='zeker'>" + TF.format(new Date()) + "</Time>");
            sb.append("    <MessageSequence>1</MessageSequence>");
            sb.append("    <SenderID>" + SENDERID + "</SenderID>");
            sb.append("    <ReceiverID>NPS001</ReceiverID>");// Default \91NPS001\92
            sb.append("    <RequestID>SellRequest</RequestID>");
            sb.append("    <ResponseID>SellResponse</ResponseID>");
            sb.append("  </Control>");
            sb.append("  <TRequest>");
            sb.append("    <SellRequest>");
            sb.append("      <PackageDetails>");
            sb.append("        <PackageID>" + price.getAltid() + "</PackageID>");
            sb.append("        <NumberOfAdults>" + reservation.getAdult() + "</NumberOfAdults>");
            sb.append("        <NumberOfChildren>" + reservation.getChild() + "</NumberOfChildren>");
            sb.append("        <NumberOfBabies>0</NumberOfBabies>");
            sb.append("        <DepartureDate>" + DF.format(reservation.getFromdate()) + "</DepartureDate>");
            sb.append("        <Duration DurationType='dagen'>" + reservation.getDuration(Time.DAY).intValue()
                    + "</Duration>");
            sb.append("      </PackageDetails>");
            sb.append("    </SellRequest>");
            sb.append("  </TRequest>");
            sb.append("</TravelMessage>");
            rq = sb.toString();

            // reservation.
            // sequence SellRequest.xml -> AssignRequest -> BookRequest
            LOG.debug("\nSellRequest rq: \n" + rq + "\n");
            LOG.error("Block 6 entry");
            rs = getConnection(rq);
            LOG.error("Block 7 entry");
            LOG.debug("\nSellRequest rs: \n" + rs + "\n");

            // AssignResuest.xml
            sb = new StringBuilder();
            sb.append("<?xml version='1.0' ?>");
            sb.append("<TravelMessage VersionID='1.8N'>");
            sb.append("  <Control Language='NL' Test='nee'>");// + getXMLTestAttrubuiteStatus() + "'>");
            sb.append("    <SenderSessionID>" + SenderSessionID + "</SenderSessionID>");
            sb.append("    <ReceiverSessionID>" + ReceiverSessionID + "</ReceiverSessionID>");
            sb.append("    <Date>" + DF.format(new Date()) + "</Date>");
            sb.append("    <Time Reliability='zeker'>" + TF.format(new Date()) + "</Time>");
            sb.append("    <MessageSequence>1</MessageSequence>");
            sb.append("    <SenderID>" + SENDERID + "</SenderID>");
            sb.append("    <ReceiverID>NPS001</ReceiverID>");
            sb.append("    <RequestID>AssignRequest</RequestID>");
            sb.append("    <ResponseID>AssignResponse</ResponseID>");
            sb.append("  </Control>");
            sb.append("  <TRequest>");
            sb.append("    <AssignRequest>");
            sb.append("      <PaxDetails>");
            sb.append("        <PaxDescription>");
            sb.append("          <PaxID>P01</PaxID>");
            sb.append("          <Initials>" + customer.getFirstName().substring(0, 1) + "</Initials>");
            sb.append("          <Infix>''</Infix>");
            sb.append("          <Name>" + customer.getFamilyName() + "</Name>");
            sb.append("          <Gender>m</Gender>");
            sb.append("        </PaxDescription>");
            sb.append("        <HomeStay>");
            sb.append("          <Name>" + customer.getName() + "</Name>");
            sb.append("          <TelHome>" + customer.getDayphone() + "</TelHome>");
            sb.append("        </HomeStay>");
            sb.append("      </PaxDetails>");
            sb.append("      <PaxAssignment>");
            sb.append("        <AccoAssignment>");
            sb.append("          <AccommodationID>" + "A" + product.getAltid() + "</AccommodationID>");
            // <AccommodationID> 'A' + HouseID, e.g. 'A1712' if the XML contained <HouseID>1712</HouseID>.
            sb.append("          <ArrivalDate>" + DF.format(reservation.getFromdate()) + "</ArrivalDate>");
            sb.append("          <Duration DurationType='dagen'>" + reservation.getDuration(Time.DAY).intValue()
                    + "</Duration>");
            sb.append("          <UnitAssignment>");
            sb.append("            <UnitID>U01</UnitID>");
            sb.append("            <Quantity>1</Quantity>");
            sb.append("            <RoomAssignment>");
            sb.append("              <Sequence>1</Sequence>");
            sb.append("              <PaxID>P01</PaxID>");
            sb.append("            </RoomAssignment>");
            sb.append("          </UnitAssignment>");
            sb.append("        </AccoAssignment>");
            sb.append("      </PaxAssignment>");
            sb.append("    </AssignRequest>");
            sb.append("  </TRequest>");
            sb.append("</TravelMessage>");

            rq = sb.toString();
            LOG.debug("\nAssignRequest rq: \n" + rq + "\n");
            rs = getConnection(rq);
            LOG.debug("\nAssignRequest rs: \n" + rs + "\n");

            // /BookRequest.xml
            sb = new StringBuilder();
            sb.append("<?xml version='1.0' ?>");
            sb.append("<TravelMessage VersionID='1.8N'>");
            sb.append("  <Control Language='NL' Test='nee'>");// + getXMLTestAttrubuiteStatus() + "'>");
            sb.append("    <SenderSessionID>" + SenderSessionID + "</SenderSessionID>");
            sb.append("    <ReceiverSessionID>" + ReceiverSessionID + "</ReceiverSessionID>");
            sb.append("    <Date>" + DF.format(new Date()) + "</Date>");
            sb.append("    <Time Reliability='zeker'>" + TF.format(new Date()) + "</Time>");
            sb.append("    <MessageSequence>1</MessageSequence>");
            sb.append("    <SenderID>" + SENDERID + "</SenderID>");
            sb.append("    <ReceiverID>NPS001</ReceiverID>");
            sb.append("    <RequestID>BookRequest</RequestID>");
            sb.append("    <ResponseID>BookResponse</ResponseID>");
            sb.append("  </Control>");
            sb.append("  <TRequest>");
            sb.append("    <BookRequest>");
            sb.append("      <PaxDetails>");
            sb.append("        <PaxDescription>");
            sb.append("          <PaxID>P01</PaxID>");
            sb.append("          <Initials>" + customer.getFirstName().substring(0, 1) + "</Initials>");
            sb.append("          <Infix>" + "de" + "</Infix>");
            sb.append("          <Name>" + customer.getFamilyName() + "</Name>");
            sb.append("          <Gender>m</Gender>");
            sb.append("        </PaxDescription>");
            sb.append("        <Contact>");
            sb.append("          <Initials>" + customer.getFirstName().substring(0, 1) + "</Initials>");
            sb.append("          <Name>" + customer.getFamilyName() + "</Name>");
            sb.append("          <Gender>m</Gender>");
            sb.append("          <Address>" + customer.getLocalAddress() + "</Address>");
            sb.append("          <Zipcode>" + customer.getPostalcode() + "</Zipcode>"); ///makse sure their is a value
            sb.append("          <Place>" + customer.getLocalAddress() + "</Place>");
            sb.append("          <Country>" + customer.getCountry() + "</Country>");
            sb.append("          <TelHome>" + customer.getDayphone() + "</TelHome>"); // TODO should be nightphone
            sb.append("          <TelWork>" + customer.getDayphone() + "</TelWork>");
            sb.append("          <TelMobile>" + customer.getDayphone() + "</TelMobile>");
            sb.append("          <Email>" + customer.getEmailaddress() + "</Email>");
            sb.append("          <BankAccount>0000</BankAccount>");
            sb.append("        </Contact>");
            sb.append("        <HomeStay>");
            sb.append("          <Name>" + customer.getName() + "</Name>");
            sb.append("          <TelHome>" + customer.getDayphone() + "</TelHome>");
            sb.append("        </HomeStay>");
            sb.append("      </PaxDetails>");
            sb.append("      <PaxAssignment>");
            sb.append("        <AccoAssignment>");
            sb.append("          <AccommodationID>" + "A" + product.getAltid() + "</AccommodationID>");
            sb.append("          <ArrivalDate>" + DF.format(reservation.getFromdate()) + "</ArrivalDate>");
            sb.append("          <Duration DurationType='dagen'>" + reservation.getDuration(Time.DAY).intValue()
                    + "</Duration>");
            sb.append("          <UnitAssignment>");
            sb.append("            <UnitID>U01</UnitID>");
            sb.append("            <Quantity>1</Quantity>");
            sb.append("            <RoomAssignment>");
            sb.append("              <Sequence>1</Sequence>");
            sb.append("              <PaxID>P01</PaxID>");
            sb.append("            </RoomAssignment>");
            sb.append("          </UnitAssignment>");
            sb.append("        </AccoAssignment>");
            sb.append("      </PaxAssignment>");
            sb.append("    </BookRequest>");
            sb.append("  </TRequest>");
            sb.append("</TravelMessage>");

            rq = sb.toString();
            LOG.debug("\nBookRequest rq: \n" + rq + "\n");

            createBooking(rq, reservation, timestamp, result);
        } catch (Throwable x) {
            reservation.setMessage(x.getMessage());
            reservation.setState(Reservation.State.Cancelled.name());
            LOG.error(x.getMessage());
        }
        sqlSession.getMapper(ReservationMapper.class).update(reservation);
        LOG.error(">>>NextPax CreateBooking finished");
        MonitorService.monitor(message, new Date(timestamp));
    }

    /**
     * Read reservation.
     * 
     * @param sqlSession the current SQL session.
     * @param reservation the reservation to be read.
     */
    @Override
    public void readReservation(SqlSession sqlSession, Reservation reservation) {
        Date timestamp = new Date();
        String message = "readReservation altid " + reservation.getAltid();
        LOG.debug(message);
        try {
            throw new ServiceException(Error.service_absent, "NextPax readReservation()");
        } catch (Throwable x) {
            reservation.setMessage(x.getMessage());
            LOG.error(x.getMessage());
        }
        MonitorService.monitor(message, timestamp);
    }

    /**
     * Update reservation.
     * 
     * @param sqlSession the current SQL session.
     * @param reservation the reservation to be updated.
     */
    @Override
    public void updateReservation(SqlSession sqlSession, Reservation reservation) {
        Date timestamp = new Date();
        String message = "updateReservation " + reservation.getId();
        LOG.debug(message);
        try {
            throw new ServiceException(Error.service_absent, "NextPax updateReservation()");
        } catch (Throwable x) {
            reservation.setMessage(x.getMessage());
            LOG.error(x.getMessage());
        }
        MonitorService.monitor(message, timestamp);
    }

    /**
     * Confirm reservation.
     * 
     * @param sqlSession the current SQL session.
     * @param reservation the reservation to be confirmed.
     */
    @Override
    public void confirmReservation(SqlSession sqlSession, Reservation reservation) {
        Date timestamp = new Date();
        String message = "confirmReservation " + reservation.getAltid();
        LOG.debug(message);
        try {
            Product product = sqlSession.getMapper(ProductMapper.class).read(reservation.getProductid());
            Party customer = sqlSession.getMapper(PartyMapper.class).read(reservation.getCustomerid());
            WebClient webClient = WebClient.create(BASE_NEXTPAX_URL);
            webClient.path("comm/bookingnet_confirm_option_novasol.php");
            webClient.accept(MediaType.TEXT_XML_TYPE);
            webClient.query("reservation_number", reservation.getAltid()).query("sender_id", SENDERID)
                    .query("house_id", product.getAltid()).query("email_address", customer.getEmailaddress());
            Response response = webClient.get();
            if (response.getStatus() != 200) {
                throw new ServiceException(Error.reservation_confirmation);
            }
        } catch (Throwable x) {
            reservation.setMessage(x.getMessage());
            LOG.error(x.getMessage());
        }
        MonitorService.monitor(message, timestamp);
    }

    /**
     * Cancel reservation.
     * 
     * @param sqlSession the current SQL session.
     * @param reservation the reservation to be cancelled.
     */
    @Override
    public void cancelReservation(SqlSession sqlSession, Reservation reservation) {
        Date timestamp = new Date();
        String message = "cancelReservation " + reservation.getAltid();
        LOG.debug(message);
        try {
            Product product = sqlSession.getMapper(ProductMapper.class).read(reservation.getProductid());
            // Example of URL: 
            // https://secure.nextpax.com/comm/bookingnet_cancel_novasol.php?
            // reservation_number=[NOVASOL_RESERVATION_NUMBER]
            // &sender_id=[YOUR_SENDER_ID]
            // &house_id=[NEXTPAX_HOUSE_ID]
            // &email_address=[CUSTOMER_EMAIL]
            String email = "";
            if (!reservation.getEmailaddress().isEmpty()) {
                email = reservation.getEmailaddress();
            } else {
                Party renter = sqlSession.getMapper(PartyMapper.class).read(reservation.getCustomerid());
                email = renter.getEmailaddress();
            }
            String customUrl = CANCELLATION_URL + "reservation_number=" + reservation.getAltid() + // RESERVATION_NUMBER
                    "&sender_id=" + SENDERID + // SENDER_ID (SENDERID)
                    "&house_id=" + product.getAltid() + // HOUSE_ID (ALTID)
                    "&email_address=" + email; // CUSTOMER_EMAIL
            URL url = new URL(customUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setDoOutput(true);
            connection.connect();

            if (connection.getResponseCode() != 200) {
                throw new RuntimeException("HTTP:" + connection.getResponseCode() + " URL " + url);
            }

            SAXBuilder parser = new SAXBuilder();
            Document document = parser.build(connection.getInputStream());
            Element rootNode = document.getRootElement();
            connection.disconnect();

            if (rootNode.getChild("Success") != null) {
                message = rootNode.getChildText("Success");
            } else if (rootNode.getChild("Error") != null) {
                message = rootNode.getChildText("Error");
                throw new ServiceException(Error.reservation_api, message);
            } else {
                message = "Something went wrong, we didn't receive any response from NextPax API";
                throw new ServiceException(Error.reservation_api, message);
            }

            LOG.debug(message);

        } catch (Throwable x) {
            reservation.setMessage(x.getMessage());
        }
        MonitorService.monitor(message, timestamp);
    }

    public void extractUniqueAdditionalFees(String[] srcs, String[] dests) {
        int i = 0;
        for (String src : srcs) {
            extractUniqueAdditionalFees(src, dests[i]);
            i++;
        }
    }

    public void extractUniqueAdditionalFees(String src, String dest) {
        BufferedWriter bw = null;

        try {
            SAXBuilder parser = new SAXBuilder();
            Document document = parser.build(new File(src));
            Element rootNode = document.getRootElement();

            bw = new BufferedWriter(new FileWriter(dest));
            HashSet<String> fees = new HashSet<String>();

            List<Element> addCosts = rootNode.getChildren("AdditionalCosts");

            for (Element addCost : addCosts) {

                List<Element> costs = addCost.getChildren("AdditionalCost");
                for (Element costData : costs) {
                    String costCode = costData.getChildText("CostCode");
                    String costType = costData.getChildText("CostType");
                    String costAmountType = costData.getChildText("CostAmountType");

                    String fee;
                    StringBuilder str = new StringBuilder();
                    StringBuilder fullStr = new StringBuilder();

                    str.append(costCode).append(" ").append(costType).append(" ").append(costAmountType);
                    fee = str.toString();

                    if (!fees.contains(fee)) {
                        fees.add(fee);
                        bw.write(str.append("\n").toString());
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (bw != null) {
                    bw.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void extractAdditionalFees(String[] srcs, String[] dests) {
        int i = 0;
        for (String src : srcs) {
            extractAdditionalFees(src, dests[i]);
            i++;
        }
    }

    public void extractAdditionalFees(String src, String dest) {
        BufferedWriter bw = null;

        try {
            SAXBuilder parser = new SAXBuilder();
            Document document = parser.build(new File(src));
            Element rootNode = document.getRootElement();

            bw = new BufferedWriter(new FileWriter(dest));
            HashMap<String, Integer> fees = new HashMap<String, Integer>();

            List<Element> addCosts = rootNode.getChildren("AdditionalCosts");

            for (Element addCost : addCosts) {

                List<Element> costs = addCost.getChildren("AdditionalCost");
                //Element costData = addCost.getChild("AdditionalCost");
                for (Element costData : costs) {
                    String costCode = costData.getChildText("CostCode");
                    String costType = costData.getChildText("CostType");
                    String costAmountType = costData.getChildText("CostAmountType");

                    String fee;
                    StringBuilder str = new StringBuilder();
                    StringBuilder fullStr = new StringBuilder();

                    str.append(costCode).append(" ").append(costType).append(" ").append(costAmountType);
                    fullStr.append(addCost.getChildText("HouseID")).append(" ").append(str).append("\n");
                    fee = str.toString();

                    if (!fees.containsKey(fee)) {
                        fees.put(fee, 0);
                        bw.write(fullStr.toString());
                        continue;
                    }
                    if (fees.get(fee) < 9) {
                        fees.put(fee, fees.get(fee) + 1);
                        bw.write(fullStr.toString());
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (bw != null) {
                    bw.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Transfer accommodation alerts.
     * 
     * @param sqlSession the current SQL session.
     */
    @Override
    public synchronized void readAlerts() {
        Date version = new Date();

        LOG.debug("readAlerts NextpaxAPIKEY: " + getApikey() + "STARTED");
        int i = 0;
        String message = "readAlerts " + getAltpartyid();
        LOG.debug(message);
        String fn = null;
        String language;
        String text;
        String startdate;
        String enddate;
        float deposit = 0;
        final SqlSession sqlSession = RazorServer.openSession();
        String partyId = getAltpartyid();

        SAXBuilder parser = new SAXBuilder();
        Document document;
        net.cbtltd.shared.Alert action = new net.cbtltd.shared.Alert();
        try {

            fn = "paxgenerator_house_notices_" + getApikey() + ".xml";
            StringBuilder sb = new StringBuilder();
            try {
                BufferedReader br = new BufferedReader(new InputStreamReader(ftp(fn)));
                String line;
                while ((line = br.readLine()) != null) {
                    while (line.contains("&")) {
                        line = line.replace("&", "");
                    }
                    sb.append(line);
                }
                br.close();
            } catch (Exception ex) {
                ex.printStackTrace();
            }

            document = parser.build(new ByteArrayInputStream(sb.toString().getBytes()));
            Element rootNode = document.getRootElement();
            List<Element> notices = rootNode.getChildren("Notices");

            for (Element note : notices) {
                String altid = note.getChildText("HouseID");
                Product product = sqlSession.getMapper(ProductMapper.class)
                        .altread(new NameId(getAltpartyid(), altid));
                if (product == null) {
                    LOG.error(Error.product_id.getMessage());
                    continue;
                }

                HashMap<String, String> texts = new HashMap<String, String>();
                List<Element> descriptions = note.getChildren("Notice");
                for (Element description : descriptions) {
                    language = description.getChildText("Language");
                    text = description.getChildText("Text");

                    String trimText = text.trim();
                    int depositIndex = trimText.indexOf("deposit:");

                    if (depositIndex >= 0) {
                        deposit = Float.parseFloat(
                                trimText.substring(depositIndex + 9, trimText.indexOf(" ", depositIndex + 9))
                                        .replace(",", "."));
                        LOG.debug("House deposit: " + deposit);
                    }

                    startdate = description.getChildText("From");
                    enddate = description.getChildText("Until");

                    action.setEntitytype(NameId.Type.Product.name());
                    action.setEntityid(product.getId());
                    action.setFromdate(DF.parse(startdate));
                    action.setTodate(DF.parse(enddate));
                    action.setLanguage(language);
                    action.setName(text);

                    net.cbtltd.shared.Alert duplicate = sqlSession.getMapper(AlertMapper.class).duplicate(action);
                    if (duplicate == null) {
                        sqlSession.getMapper(AlertMapper.class).create(action);
                    } else {
                        sqlSession.getMapper(AlertMapper.class).update(action);
                    }

                    product.setSecuritydeposit((double) deposit);
                    sqlSession.getMapper(ProductMapper.class).update(product);
                    sqlSession.commit();
                    LOG.debug(i++ + " " + action.toString());
                }
                sqlSession.commit();
            }
        } catch (JDOMException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
            delete(fn);
        }
        LOG.debug("readAlerts NextpaxAPIKEY: " + getApikey() + " DONE");
        MonitorService.monitor(message, version);
    }

    @Override
    public void readPrices() {
        Date version = new Date();
        String message = "readPrices NextpaxAPIKEY: " + this.getApikey() + "STARTED";
        LOG.debug(message);

        final SqlSession sqlSession = RazorServer.openSession();
        try {
            // rates

            Element rootNode = document.getRootElement();
            List<Element> houses = rootNode.getChildren("offer", ns);
            int ij = 0;
            for (Element house : houses) {
                ij++;
                if (ij > 2260) {
                    break;
                }
                if (ij < 2100) {
                    continue;
                }
                System.out.println("Product prices: " + ij);
                System.out.println("product #" + ij);
                String altid = house.getAttributeValue("internal-id");
                Product product = PartnerService.getProduct(sqlSession, getAltpartyid(), altid);

                if (product == null) {
                    continue;
                }

                Element costs = house.getChild("rateperiods", ns);
                if (costs == null) {
                    continue;
                }
                List<Element> costList = costs.getChildren("rateperiod", ns);
                for (Element cost : costList) {
                    try {
                        LOG.debug("cost " + cost);

                        String from = cost.getChildText("startdate", ns);
                        String until = cost.getChildText("enddate", ns);
                        String costcurrency = cost.getChildText("currency", ns);

                        Double dailyrate = 0d;
                        String dailyrateS = cost.getChildText("dailyrate", ns);
                        if (dailyrateS != null && !dailyrateS.isEmpty())
                            dailyrate = Double.valueOf(dailyrateS);

                        Double weekendrate = 0d;
                        String weekendrateS = cost.getChildText("weekendrate", ns);
                        if (weekendrateS != null && !weekendrateS.isEmpty())
                            weekendrate = Double.valueOf(weekendrateS);

                        Double weekrate = 0d;
                        String weekrateS = cost.getChildText("weekrate", ns);
                        if (weekrateS != null && !weekrateS.isEmpty())
                            weekrate = Double.valueOf(weekrateS);

                        Double monthrate = 0d;
                        String monthrateS = cost.getChildText("monthrate", ns);
                        if (monthrateS != null && !monthrateS.isEmpty())
                            monthrate = Double.valueOf(monthrateS);

                        String costcode = "";
                        Double costamount = 0.0;
                        for (int i = 0; i < 4; i++) {
                            switch (i) {
                            case 0:
                                costamount = dailyrate;
                                costcode = "Price per day";
                                break;
                            case 1:
                                costamount = weekendrate;
                                costcode = "Price per weekend";
                                break;
                            case 2:
                                costamount = weekrate;
                                costcode = "Price per week";
                                break;
                            case 3:
                                costamount = monthrate;
                                costcode = "Price per month";
                                break;
                            default:
                                break;
                            }

                            System.out.println("costamount = " + costamount);
                            if (costamount != 0.0) {

                                Price price = new Price();
                                price.setPartyid(getAltpartyid());
                                price.setEntitytype(NameId.Type.Product.name());
                                price.setEntityid(product.getId());// productID
                                price.setCurrency(costcurrency);
                                price.setQuantity(0.0);
                                price.setName(costcode);
                                price.setType(NameId.Type.Reservation.name());
                                price.setDate(DF.parse(from));
                                price.setTodate(DF.parse(until));
                                price.setAvailable(1);

                                LOG.debug("price " + price);
                                Price exists = sqlSession.getMapper(PriceMapper.class).exists(price);
                                if (exists == null) {
                                    sqlSession.getMapper(PriceMapper.class).create(price);
                                } else {
                                    price = exists;
                                }

                                // price.setAltid(costcode);
                                price.setAltpartyid(getAltpartyid());
                                price.setFactor(1.0);
                                price.setOrganizationid(getAltpartyid());
                                price.setRule(Price.Rule.FixedRate.name());
                                price.setState(Price.CREATED);
                                price.setValue(Double.valueOf(costamount));
                                price.setMinimum(0.0);
                                price.setVersion(version);
                                sqlSession.getMapper(PriceMapper.class).update(price);
                                // sqlSession.getMapper(PriceMapper.class).cancelversion(price);
                                // If it just has not been updated we are deleting it.
                                // Will decide how we want to handle updates
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                sqlSession.commit();
                LOG.debug("readPrices NextpaxAPIKEY: " + this.getApikey() + "DONE");
            }
        } catch (Throwable x) {
            sqlSession.rollback();
            LOG.error(x.getMessage());
            x.printStackTrace();
        } finally {
            sqlSession.close();
        }
        MonitorService.monitor(message, version);
    }

    public void readFeesOld() {

        Date version = new Date();
        String message = "readPrices NextpaxAPIKEY: " + this.getApikey() + "STARTED";
        LOG.debug(message);

        String fn = "c:\\parsing\\p.xml";

        final SqlSession sqlSession = RazorServer.openSession();
        try {

            SAXBuilder parser = new SAXBuilder();

            //   Document document = parser.build(ftp(fn));
            Document document = parser.build(new FileInputStream(fn));

            Element rootNode = document.getRootElement();
            List<Element> houses = rootNode.getChildren("AdditionalCosts");
            for (Element house : houses) {
                String altid = house.getChildText("HouseID");
                Product product = PartnerService.getProduct(sqlSession, getAltpartyid(), altid);

                if (product == null) {
                    continue;
                }

                List<Element> costs = house.getChildren("AdditionalCost");
                for (Element cost : costs) {
                    LOG.debug("cost " + cost);
                    String costcode = cost.getChildText("CostCode");
                    String costtype = cost.getChildText("CostType");
                    String costamount = cost.getChildText("CostAmount");
                    String costamounttype = cost.getChildText("CostAmountType");
                    String costcurrency = cost.getChildText("CostCurrency");
                    String number = cost.getChildText("Number");
                    String from = cost.getChildText("From");
                    String until = cost.getChildText("Until");

                    Fee feeObject = new Fee();
                    feeObject.setProductId(product.getId());
                    feeObject.setPartyId(product.getAltpartyid());
                    //feeObject.setState(Fee.CREATED);

                    feeObject.setName(""/*getCostCode(costcode)*/);
                    feeObject.setEntityType(21);
                    sqlSession.getMapper(FeeMapper.class).create(feeObject);

                }
                sqlSession.commit();
                LOG.debug("readPrices NextpaxAPIKEY: " + this.getApikey() + "DONE");
            }
        } catch (Throwable x) {
            sqlSession.rollback();
            LOG.error(x.getMessage());
            // x.printStackTrace();
        } finally {
            sqlSession.close();
            delete(fn);
        }
        MonitorService.monitor(message, version);

    }

    public void readFees() {
        Date version = new Date();
        String message = "readFees Yandex";
        LOG.debug(message);

        final SqlSession sqlSession = RazorServer.openSession();
        try {
            // fees

            Element rootNode = document.getRootElement();
            List<Element> houses = rootNode.getChildren("offer", ns);
            int ij = 0;
            for (Element house : houses) {
                ij++;
                System.out.println("Product fees: " + ij);
                //            if (ij>10) {
                //               break;
                //            }
                String altid = house.getAttributeValue("internal-id");
                Product product = PartnerService.getProduct(sqlSession, getAltpartyid(), altid);

                if (product == null) {
                    continue;
                }

                Element fees = house.getChild("fees", ns);
                if (fees == null) {
                    continue;
                }
                List<Element> feeList = fees.getChildren("fee", ns);
                for (Element fee : feeList) {
                    try {
                        LOG.debug("fee " + fee);

                        String feecode = fee.getAttributeValue("type");
                        String feecurrency = fee.getChildText("currency", ns);

                        Double feecost = 0d;
                        String feecostS = fee.getChildText("cost", ns);
                        if (feecostS != null && !feecostS.isEmpty())
                            feecost = Double.valueOf(feecostS);

                        Fee feeObject = new Fee();
                        feeObject.setProductId(product.getId());
                        feeObject.setPartyId(product.getAltpartyid());
                        feeObject.setState(Fee.CREATED);
                        feeObject.setUnit(1);
                        feeObject.setValueType(1);

                        feeObject.setName(feecode);
                        feeObject.setEntityType(21);
                        feeObject.setCurrency(feecurrency);
                        feeObject.setValue(feecost);

                        Fee exists = sqlSession.getMapper(FeeMapper.class).exists(feeObject);
                        if (exists == null) {
                            sqlSession.getMapper(FeeMapper.class).create(feeObject);
                        }

                        /*Price price = new Price();
                        price.setPartyid(getAltpartyid());
                        price.setEntitytype(NameId.Type.Product.name());
                        price.setEntityid(product.getId());// productID
                        price.setCurrency(feecurrency);
                        price.setQuantity(0.0);
                        price.setName(feecode);
                        price.setType(NameId.Type.Tax.name());
                        price.setAvailable(1);
                            
                        Date date = new Date();
                        price.setDate(date);
                        price.setTodate(date);
                            
                        LOG.debug("price " + price);
                        Price exists = sqlSession.getMapper(PriceMapper.class).exists(price);
                        if (exists == null) {
                           sqlSession.getMapper(PriceMapper.class).create(price);
                        } else {
                           price = exists;
                        }
                            
                        price.setAltpartyid(getAltpartyid());
                        price.setFactor(1.0);
                        price.setOrganizationid(getAltpartyid());
                        price.setRule(Price.Rule.FixedRate.name());
                        price.setState(Price.CREATED);
                        price.setValue(Double.valueOf(feecost));
                        price.setMinimum(0.0);
                        price.setVersion(version);
                        sqlSession.getMapper(PriceMapper.class).update(price);*/
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                sqlSession.commit();
                LOG.debug("readFees Yandex DONE");
            }
        } catch (Throwable x) {
            sqlSession.rollback();
            LOG.error(x.getMessage());
            x.printStackTrace();
        } finally {
            sqlSession.close();
        }
        MonitorService.monitor(message, version);
    }

    /**
     * Transfer accommodation products.
     * 
     * @param sqlSession the current SQL session.
     */
    @Override
    public synchronized void readProducts() {
        String message = "Read Products from Yandex xml";
        LOG.debug(message);
        Date version = new Date();
        HashSet<String> productsProceeded = new HashSet<String>();

        try {
            document = parseXML(new File(System.getProperty("user.dir") + "\\doc\\advToAbook.xml"));
            //document = parseXML(new URL("http://staytoday.ru/advToAbook.xml"));
            ns = document.getRootElement().getNamespace();

            //testStayToday();

            //createOrUpdateProducts(productsProceeded);

            //    readHousePropertyCodes();
            //    updateInactiveProducts(productsProceeded);

            readDescriptions();
            //readImages();

            //    setLocation();

            //readPrices();
            //readFees();
            //    readSchedule();

            //MonitorService.monitor(message, version);
        } catch (Throwable x) {
            x.printStackTrace();
            LOG.error(x.getStackTrace());
        }
    }

    private Document parseXML(File file) {
        try {
            return (new SAXBuilder()).build(file);
        } catch (Exception e) {
            LOG.error("Could not parse Yandex XML, reason: " + e.getMessage());
            return null;
        }
    }

    private Document parseXML(URL url) {
        try {
            return (new SAXBuilder()).build(url);
        } catch (Exception e) {
            LOG.error("Could not parse Yandex XML, reason: " + e.getMessage());
            return null;
        }
    }

    private void updateInactiveProducts(HashSet<String> productsProceeded) {
        LOG.debug("Starting update for inactive products");
        String partyId = getAltpartyid();
        final SqlSession sqlSession = RazorServer.openSession();
        HashSet<String> activeProducts = new HashSet<String>();
        activeProducts.addAll(sqlSession.getMapper(ProductMapper.class).activeProductAltIdListBySupplier(partyId));
        try {
            activeProducts.removeAll(productsProceeded);
            for (String altId : activeProducts) {
                Product product = sqlSession.getMapper(ProductMapper.class).altread(new NameId(partyId, altId));
                product.setState(Product.FINAL);
                sqlSession.getMapper(ProductMapper.class).update(product);
                LOG.debug("Product " + product.getName() + ", " + product.getId()
                        + " inactive. Moving to Final state.");
            }
            LOG.debug("Update for inactive products finished, no errors");
        } catch (Throwable e) {
            LOG.error("Could not finish update for inactive products, reason: " + e.getMessage());
        }
    }

    public void testCreateOrUpdateProducts() {
        HashSet<String> productsProceeded = new HashSet<String>();
        createOrUpdateProducts(productsProceeded);
    }

    private void testStayToday() {
        int i = 0;
        int j = 0;
        try {
            Element rootNode = document.getRootElement();
            List<Element> houses = rootNode.getChildren("offer", ns);

            for (Element house : houses) {
                ArrayList<String> attributes = new ArrayList<String>();
                String altid = house.getAttributeValue("internal-id");
                System.out.println("altid = " + altid);
                String name = house.getChildText("name", ns); // sometimes empty
                name = "";

                Element locationNode = house.getChild("location", ns);

                String longitudeValue = locationNode.getChildText("longitude", ns);
                String latitudeValue = locationNode.getChildText("latitude", ns);
                Double longitude = longitudeValue == null ? null : Double.valueOf(longitudeValue);
                Double latitude = latitudeValue == null ? null : Double.valueOf(latitudeValue);

                String country = locationNode.getChildText("country", ns);
                String place = locationNode.getChildText("city", ns);
                String address = locationNode.getChildText("address", ns); // never used yet

                Element rateperiods = house.getChild("rateperiods", ns);
                String currency = null;
                if (rateperiods != null) {
                    List<Element> rateperiodList = rateperiods.getChildren("rateperiod", ns);
                    if (rateperiodList.size() > 0) {
                        currency = rateperiodList.get(0).getChildText("currency", ns);
                    }
                }

                i++;
                if (currency != null) {
                    j++;
                }

                Element details = house.getChild("details", ns);

                String maxpersons = details.getChildText("maximumOccupancy", ns);

                String region = house.getChildText("Region", ns); // might be empty? TODO check what to do in such case
                if (StringUtils.isNotBlank(region) && region.length() > 2) {
                    region = region.substring(2);
                }
                String zipCode = house.getChildText("ZipCode", ns);
                String minchildren = house.getChildText("MinChildren", ns); // MinChildren

                // attribute list
                String pool = house.getChildText("Pool", ns);
                String tennis = house.getChildText("Tennis", ns);
                String ski = house.getChildText("Ski", ns);
                String type = house.getChildText("Type", ns);
                String numberofstars = house.getChildText("NumberOfStars", ns);
                String numberofpets = house.getChildText("NumberOfPets", ns);

                // String water = house.getChildText("Water"); // mapping is not known, probable match LOC33
                // String arrivalday = house.getChildText("ArrivalDay"); // we may need this.
                // String brand = house.getChildText("Brand");

                // build the list

                if (StringUtils.isBlank(numberofstars)) {
                    numberofstars = "0";
                }

                //=== suitability ===//
                Element suitability = house.getChild("suitability", ns);

                String FAM = suitability.getChildText("is_family", ns);
                if (StringUtils.isNotBlank(FAM) && FAM.equals("true")) {
                    attributes.add(net.cbtltd.shared.Attribute.FAM);
                }
                String SMO = suitability.getChildText("is_nosmoking", ns);
                if (StringUtils.isNotBlank(SMO) && SMO.equals("false")) {
                    attributes.add(net.cbtltd.shared.Attribute.SMO);
                }
                String PHY = suitability.getChildText("is_invalid", ns);
                if (StringUtils.isNotBlank(PHY) && PHY.equals("true")) {
                    attributes.add(net.cbtltd.shared.Attribute.PHY);
                }
                //=== suitability ===//

                if (StringUtils.isNotBlank(pool) && pool.equals("Y")) {
                    attributes.add(ATTRIBUTES.get("pool"));
                }
                if (StringUtils.isNotBlank(tennis) && tennis.equals("Y")) {
                    attributes.add(ATTRIBUTES.get("tennis"));
                }
                if (StringUtils.isNotBlank(ski) && ski.equals("Y")) {
                    attributes.add(ATTRIBUTES.get("ski"));
                }

                if (StringUtils.isNotBlank(numberofpets) && Integer.parseInt(numberofpets) > 0) {
                    attributes.add(ATTRIBUTES.get("All pets"));
                }

                if (StringUtils.isNotBlank(type) && StringUtils.isNotBlank(HOUSE_TYPES.get(type))) {
                    if (type.equals("APO")) {
                        String[] apartmentTypes = HOUSE_TYPES.get(type).split(",");
                        for (String ota : apartmentTypes) {
                            attributes.add(ota);
                        }
                    } else {
                        attributes.add(HOUSE_TYPES.get(type));
                    }
                } else {
                    LOG.debug("Property type is not available for product <" + altid + ">: " + type);
                }

                // we can use these later on when we build POI database. Nextpax provides separate feed for holiday parks
                String holidaypark = house.getChildText("HolidayPark");
                String skiarea = house.getChildText("SkiArea");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("errors = " + (i - j));
    }

    private void createOrUpdateProducts(HashSet<String> productsProceeded) {
        long startTime = System.currentTimeMillis();
        final SqlSession sqlSession = RazorServer.openSession();

        String partyId = getAltpartyid();
        String fileName = "staytoday.xml";
        Map<String, Location> locations = new HashMap<String, Location>();
        try {
            // House attributes.
            RelationService.load(sqlSession, Downloaded.PRODUCT_DOWNLOAD_DATE, partyId, new Date().toString());
            SAXBuilder parser = new SAXBuilder();

            long startParsing = System.currentTimeMillis();
            Element rootNode = document.getRootElement();
            List<Element> houses = rootNode.getChildren("offer", ns);
            System.out.println(rootNode.getNamespace());
            System.out.println(rootNode.getChild("generation-date", ns).getName());
            System.out.println("Number of properties " + houses.size());
            int i = 0;
            for (Element house : houses) {
                i++;
                if (i < 433) {
                    continue;
                }
                System.out.println("Products number: " + i);
                //try {
                ArrayList<String> attributes = new ArrayList<String>();
                // ArrayList<NameId> images = new ArrayList<NameId>();
                // StringBuilder description = new StringBuilder();

                String altid = house.getAttributeValue("internal-id");
                String name = house.getChildText("name", ns); // sometimes empty
                name = "";

                Element locationNode = house.getChild("location", ns);

                String longitudeValue = locationNode.getChildText("longitude", ns);
                String latitudeValue = locationNode.getChildText("latitude", ns);
                Double longitude = longitudeValue == null ? null : Double.valueOf(longitudeValue);
                Double latitude = latitudeValue == null ? null : Double.valueOf(latitudeValue);

                String country = locationNode.getChildText("country", ns);
                String place = locationNode.getChildText("city", ns);
                String address = locationNode.getChildText("address", ns); // never used yet

                Element rateperiods = house.getChild("rateperiods", ns);
                String currency = null;
                if (rateperiods != null) {
                    List<Element> rateperiodList = rateperiods.getChildren("rateperiod", ns);
                    if (rateperiodList.size() > 0) {
                        currency = rateperiodList.get(0).getChildText("currency", ns);
                    }
                }

                Element details = house.getChild("details", ns);

                String maxpersons = details.getChildText("maximumOccupancy", ns);

                String region = house.getChildText("Region", ns); // might be empty? TODO check what to do in such case
                if (StringUtils.isNotBlank(region) && region.length() > 2) {
                    region = region.substring(2);
                }
                String zipCode = house.getChildText("ZipCode", ns);
                String minchildren = house.getChildText("MinChildren", ns); // MinChildren

                // attribute list
                String pool = house.getChildText("Pool", ns);
                String tennis = house.getChildText("Tennis", ns);
                String ski = house.getChildText("Ski", ns);
                String type = house.getChildText("Type", ns);
                String numberofstars = house.getChildText("NumberOfStars", ns);
                String numberofpets = house.getChildText("NumberOfPets", ns);

                // String water = house.getChildText("Water"); // mapping is not known, probable match LOC33
                // String arrivalday = house.getChildText("ArrivalDay"); // we may need this.
                // String brand = house.getChildText("Brand");

                // build the list

                if (StringUtils.isBlank(numberofstars)) {
                    numberofstars = "0";
                }

                //=== suitability ===//
                Element suitability = house.getChild("suitability", ns);

                String FAM = suitability.getChildText("is_family", ns);
                if (StringUtils.isNotBlank(FAM) && FAM.equals("true")) {
                    attributes.add(net.cbtltd.shared.Attribute.FAM);
                }
                String SMO = suitability.getChildText("is_nosmoking", ns);
                if (StringUtils.isNotBlank(SMO) && SMO.equals("false")) {
                    attributes.add(net.cbtltd.shared.Attribute.SMO);
                }
                String PHY = suitability.getChildText("is_invalid", ns);
                if (StringUtils.isNotBlank(PHY) && PHY.equals("true")) {
                    attributes.add(net.cbtltd.shared.Attribute.PHY);
                }
                //=== suitability ===//

                if (StringUtils.isNotBlank(pool) && pool.equals("Y")) {
                    attributes.add(ATTRIBUTES.get("pool"));
                }
                if (StringUtils.isNotBlank(tennis) && tennis.equals("Y")) {
                    attributes.add(ATTRIBUTES.get("tennis"));
                }
                if (StringUtils.isNotBlank(ski) && ski.equals("Y")) {
                    attributes.add(ATTRIBUTES.get("ski"));
                }

                if (StringUtils.isNotBlank(numberofpets) && Integer.parseInt(numberofpets) > 0) {
                    attributes.add(ATTRIBUTES.get("All pets"));
                }

                if (StringUtils.isNotBlank(type) && StringUtils.isNotBlank(HOUSE_TYPES.get(type))) {
                    if (type.equals("APO")) {
                        String[] apartmentTypes = HOUSE_TYPES.get(type).split(",");
                        for (String ota : apartmentTypes) {
                            attributes.add(ota);
                        }
                    } else {
                        attributes.add(HOUSE_TYPES.get(type));
                    }
                } else {
                    LOG.debug("Property type is not available for product <" + altid + ">: " + type);
                }

                // we can use these later on when we build POI database. Nextpax provides separate feed for holiday parks
                String holidaypark = house.getChildText("HolidayPark");
                String skiarea = house.getChildText("SkiArea");

                Product product = PartnerService.getProduct(sqlSession, partyId, altid);
                Location location;
                if (product != null && product.getLocationid() != null) {
                    location = sqlSession.getMapper(LocationMapper.class).read(product.getLocationid());
                } else {
                    location = locations.get(StringUtils.isNotBlank(place) ? place + country : zipCode + country);
                }
                // set location if null
                // look in the database first
                // then do a google geocode API lookup
                if (location == null
                        && (StringUtils.isBlank(place) || PATTERN_FOR_SPECIAL_CHARACTERS.matcher(place).find())) {
                    location = PartnerService.getLocation(sqlSession, zipCode, country, latitude, longitude);
                    locations.put(StringUtils.isNotBlank(place) ? place + country : zipCode + country, location);
                } else if (location == null) {
                    place = ISO8859CharacterNormalizer.decode(place);
                    location = PartnerService.getLocation(sqlSession, place, region, country, latitude, longitude,
                            zipCode);
                    locations.put(place + country, location); // will create too big map. Maybe use only location ID instead of whole object
                }

                // set the name if it is blank
                if (StringUtils.isBlank(name) && location != null) {
                    String locationName = location.getName() == null ? location.getGname() : location.getName();
                    // sometimes GeoLocation returns null, in this case, use gname.
                    locationName = locationName == null ? location.getAdminarea_lvl_1() : locationName;
                    name = "House" + " in " + locationName + " " + altid; // Set the Name to be sure it will not be null after this point.
                    if (attributes.size() > 0) {
                        ArrayList<NameId> pctList = sqlSession.getMapper(AttributeMapper.class)
                                .pctListValue(new net.cbtltd.shared.Attribute("PCT",
                                        attributes.get(0).substring("PCT".length())));
                        for (NameId attribute : pctList) { // what if list is empty?
                            name = "House in " + locationName + " " + altid;
                        }
                    }
                } // check if this might go for 'else'

                if (product == null) {
                    LOG.debug("Incative property <" + altid + ">. Updating...");
                    //according to the code, following line will give us exact property, but with inactive state.
                    product = sqlSession.getMapper(ProductMapper.class).altread(new NameId(partyId, altid));
                }
                product = createOrUpdateProductModel(location, place, region, zipCode, country, maxpersons,
                        minchildren, numberofstars, currency, latitude, longitude, name, product);

                //=== additional properties ===//
                int rooms = 0;
                try {
                    rooms = Integer.parseInt(house.getChildText("rooms", ns)); // Number of rooms.
                } catch (NumberFormatException e) {
                }
                product.setRoom(rooms);

                try {
                    product.setBathroom(Integer.parseInt(details.getChildText("bathrooms", ns))); // Number of bedrooms.
                } catch (NumberFormatException e) {
                }

                try {
                    product.setPerson(Integer.parseInt(maxpersons));
                } catch (NumberFormatException e) {
                }

                product.setPhysicaladdress(address);

                product.setState(Product.CREATED);
                //=== additional properties ===//

                sqlSession.getMapper(ProductMapper.class).update(product);
                productsProceeded.add(altid);

                RelationService.replace(sqlSession, Relation.PRODUCT_VALUE, product.getId(), product.getValues());
                RelationService.create(sqlSession, Relation.PRODUCT_OTA_ATTRIBUTE, product.getId(), attributes);

                LOG.debug(
                        i + " " + altid + " " + product.getId() + " " + product.getId() + " " + product.getName());
                sqlSession.commit();
                //} catch(Exception e) {
                //   continue;
                //}
            }
        } catch (Exception x) {
            sqlSession.rollback();
            x.printStackTrace();
            LOG.error(x.getMessage());
        } finally {
            //         sqlSession.commit(); //TODO remove? not sure if we need this
            sqlSession.close();
            delete(fileName);
        }
        LOG.debug("Time taken to complete create products for " + getApikey() + " : "
                + ((System.currentTimeMillis() - startTime)) / 1000 + " seconds.");
    }

    // Leave for now.
    private void setLocation() {
        final SqlSession sqlSession = RazorServer.openSession();
        String altid = "";
        Product product;

        long startTime = System.currentTimeMillis();
        String fileName = "paxgenerator_houses_" + getApikey() + ".xml";
        Map<String, Location> locations = new HashMap<String, Location>();
        int i = 0;
        try {
            // RelationService.load(sqlSession, Downloaded.PRODUCT_DOWNLOAD_DATE, getAltpartyid(), new Date().toString());
            SAXBuilder parser = new SAXBuilder();
            long startParsing = System.currentTimeMillis();
            Document document = null;
            document = parser.build(new File(System.getProperty("user.home") + File.separator + "PMS"
                    + File.separator + "nextpax" + File.separator + fileName));
            LOG.debug("Time taken to parse " + fileName + " : " + (System.currentTimeMillis() - startParsing)
                    + " milli seconds.");

            Element rootNode = document.getRootElement();
            List<Element> houses = rootNode.getChildren("House");
            for (Element house : houses) {
                altid = house.getChildText("HouseID");
                ArrayList<String> attributes = new ArrayList<String>();
                ArrayList<NameId> images = new ArrayList<NameId>();
                StringBuilder description = new StringBuilder();

                String country = house.getChildText("Country");
                String region = house.getChildText("Region");
                if (StringUtils.isNotBlank(region) && region.length() > 2) {
                    region = region.substring(2);
                }
                String place = house.getChildText("Place");
                String zipCode = house.getChildText("ZipCode");
                String name = house.getChildText("Name");
                String latitude = house.getChildText("Latitude");
                String longitude = house.getChildText("Longitude");
                // attribute list
                String type = house.getChildText("Type");
                // build the list
                if (StringUtils.isNotBlank(type) && StringUtils.isNotBlank(HOUSE_TYPES.get(type))) {
                    if (type.equals("APO")) {
                        String[] apartmentTypes = HOUSE_TYPES.get(type).split(",");
                        for (String ota : apartmentTypes) {
                            attributes.add(ota);
                        }
                    } else {
                        attributes.add(HOUSE_TYPES.get(type));
                    }
                } else {
                    LOG.debug("Property type is not available for product <" + altid + ">: " + type);
                }

                product = PartnerService.getProduct(sqlSession, getAltpartyid(), altid);
                if (product == null) {
                    LOG.debug("Property does not exist <" + altid + ">");
                } else if (StringUtils.isBlank(product.getLocationid())) {
                    Location location = null;
                    LOG.debug("Processing location altid/place: " + altid + " " + place);
                    location = locations.get(StringUtils.isNotBlank(place) ? place + country : zipCode + country);
                    if (StringUtils.isBlank(place) || PATTERN_FOR_SPECIAL_CHARACTERS.matcher(place).find()) {
                        if (location == null) {
                            location = PartnerService.getLocation(sqlSession, zipCode, country,
                                    latitude == null ? null : Double.valueOf(latitude),
                                    longitude == null ? null : Double.valueOf(longitude));
                            locations.put(StringUtils.isNotBlank(place) ? place + country : zipCode + country,
                                    location);
                        }
                    } else {
                        if (location == null) {
                            try {
                                place = ISO8859CharacterNormalizer.decode(place);
                            } catch (Exception e) {
                                LOG.error("Character mapping does not have mapping for place/altid/country: "
                                        + place + ":" + altid + ":" + country);
                                continue;
                            }
                            location = PartnerService.getLocation(sqlSession, place, region, country,
                                    latitude == null ? null : Double.valueOf(latitude),
                                    longitude == null ? null : Double.valueOf(longitude), zipCode);
                            locations.put(place + country, location);
                        }
                    }

                    // set the name if it is blank
                    if (StringUtils.isBlank(name)) {
                        if (attributes.size() > 0) {
                            ArrayList<NameId> pctList = sqlSession.getMapper(AttributeMapper.class)
                                    .pctListValue(new net.cbtltd.shared.Attribute("PCT",
                                            attributes.get(0).substring("PCT".length())));
                            for (NameId attribute : pctList) {
                                name = attribute.getName() + " in "
                                        + (StringUtils.isNotBlank(location.getName()) ? location.getName() : place);
                            }
                        } else {
                            name = "House" + " in "
                                    + (StringUtils.isNotBlank(location.getName()) ? location.getName() : place);
                        }
                    } else {
                        name = ISO8859CharacterNormalizer.decode(name);
                    }

                    updateProductModelForLocation(location, name, product);
                    sqlSession.getMapper(ProductMapper.class).update(product);
                    LOG.debug("Location processed altID/Name/Location: " + altid + " " + product.getName() + " "
                            + (location == null ? null : location.getName()));
                    i++;
                }
                sqlSession.commit();
            }
        } catch (GoogleLocationLimitException e) {
            sqlSession.commit();
            sqlSession.close();
            LOG.error(e.getMessage());
            LOG.debug("Processing location for house id: " + altid + " total locations processed: " + i);
        } catch (Throwable x) {
            sqlSession.rollback();
            x.printStackTrace();
            LOG.error(x.getMessage());
        } finally {
            sqlSession.close();
        }
        LOG.debug("Time taken to update houses(" + i + ")" + "locations(" + locations.size() + ") for "
                + getApikey() + " : " + ((System.currentTimeMillis() - startTime)) / 1000 + " seconds.");
    }

    private Product createOrUpdateProductModel(Location location, String place, String region, String zipCode,
            String country, String maxpersons, String minchildren, String numberofstars, String currency,
            Double latitude, Double longitude, String name, Product product) {
        if (location != null) {
            product.setLocationid(location.getId()); // if we will use only loc id, there'll be less data coming in and out between methods.
        } else {
            LOG.debug("No location is available for property: " + product.getAltid());
        }
        product.setLatitude(latitude);
        product.setLongitude(longitude);
        product.setAltitude(0.0);

        StringBuilder address = new StringBuilder();
        if (place != null && !place.isEmpty()) {
            address.append(place).append("\n");
        }
        if (region != null && !region.isEmpty()) {
            address.append(region).append("\n");
        }
        if (zipCode != null && !zipCode.isEmpty()) {
            address.append(zipCode).append("\n");
        }
        if (country != null && !country.isEmpty()) {
            address.append(country).append("\n");
        }
        product.setPhysicaladdress(address.toString());

        String pmID = String.valueOf(getPropertyManagerID(getApikey()));
        product.setAltSupplierId(pmID); // ID of propertyManager.
        product.setAltpartyid(getAltpartyid());
        product.setSupplierid(getAltpartyid());
        product.setPerson(maxpersons == null || maxpersons.isEmpty() ? 1 : Integer.valueOf(maxpersons));
        product.setChild(minchildren == null || minchildren.isEmpty() ? 1 : Integer.valueOf(minchildren));
        product.setInfant(0);
        product.setQuantity(1);
        product.setRating(Integer.valueOf(numberofstars));
        product.setCommission(getCommission());
        product.setSecuritydeposit(Product.DEFAULT_SECUIRTY_DEPOSIT);
        product.setCleaningfee(Product.DEFAULT_CLEANING_FEE);
        product.setDiscount(getDiscount());
        product.setRank(getRank());
        product.setUseonepricerow(true);
        product.setType(Product.Type.Accommodation.name());
        product.setCurrency(currency);
        product.setUnit(Unit.DAY);// don't use week ever.
        product.setWebaddress(getWebaddress());
        product.setServicedays("0000000");
        product.setCode("");
        product.setDynamicpricingenabled(false);
        product.setName(name);
        product.setAdult(0);

        return product;
    }

    private Product updateProductModelForLocation(Location location, String name, Product product) {
        if (product == null) {
            return null;
        }

        if (location != null) {
            product.setLocationid(location.getId());
        } else {
            LOG.debug("No location is available for property: " + product.getAltid());
        }
        product.setName(name);

        return product;
    }

    private void readHouseProperties() {
        long startTime = System.currentTimeMillis();

        final SqlSession sqlSession = RazorServer.openSession();
        String fileName = "paxgenerator_house_properties_" + getApikey() + ".xml";
        int updatedHouses = 0;
        try {
            long startParsing = System.currentTimeMillis();
            LOG.debug("Time taken to parse " + fileName + " : " + (System.currentTimeMillis() - startParsing)
                    + " milli seconds.");

            Element rootNode = document.getRootElement();
            List<Element> houses = rootNode.getChildren("offer");

            for (Element house : houses) {
                String altid = house.getAttributeValue("internal-id");
                Product product = PartnerService.getProduct(sqlSession, getAltpartyid(), altid, false);
                if (product == null) {
                    continue;
                }

                int rooms = 0;
                try {
                    rooms = Integer.parseInt(house.getChildText("Value")); // Number of bedrooms.
                } catch (NumberFormatException e) {
                }
                product.setRoom(rooms);
                if (rooms > 8) {
                    RelationService.create(sqlSession, Relation.PRODUCT_ATTRIBUTE, product.getId(),
                            ATTRIBUTES.get("B02") + 9);
                } else if (rooms > 0) {
                    RelationService.create(sqlSession, Relation.PRODUCT_ATTRIBUTE, product.getId(),
                            ATTRIBUTES.get("B02") + rooms);
                }

                Integer toilet = 0;
                LOG.debug("Setting properties for: " + product.getId());
                List<Element> properties = house.getChildren("Property");
                for (Element property : properties) {
                    String attrKey = property.getChildText("PropertyCode");
                    // Use `case` when we will move to JAVA 7 or higher
                    if (attrKey.equals("B01")) {
                        try {
                            product.setBathroom(Integer.parseInt(property.getChildText("Value"))); // Number of bedrooms.
                        } catch (NumberFormatException e) {
                            // do nothing...move onto next property
                        }
                    } else if (attrKey.equals("T07")) {
                        try {
                            toilet = Integer.parseInt(property.getChildText("Value"));
                        } catch (NumberFormatException e) {
                            // do nothing...move onto next property
                        }
                    } // do not have mapping do nothing. *Maybe create attributes or add into description?
                    else if (attrKey.equals("D02")) {
                        // number of double beds
                    } else if (attrKey.equals("S02")) {
                        // number of single beds
                    } else if (attrKey.equals("S03")) {
                        // number of sofas
                    } else {
                        // look up ATTRIBUTE Map
                        String attrList = ATTRIBUTES.get(attrKey);
                        if (!StringUtils.isEmpty(attrList)) {
                            RelationService.delete(sqlSession, Relation.PRODUCT_OTA_ATTRIBUTE, product.getId(),
                                    attrList);
                            // if we are running delta import....this will make sure create will not fail.
                            RelationService.create(sqlSession, Relation.PRODUCT_OTA_ATTRIBUTE, product.getId(),
                                    attrList);
                        }
                    }
                }

                product.setToilet(toilet);
                if ((product.getRoom() == null || product.getRoom() < 1) || (product.getBathroom() == null)) {
                    product.setState(Product.SUSPENDED);
                } else {
                    product.setState(Product.CREATED);
                }
                product.setAssignedtomanager(true);

                sqlSession.getMapper(ProductMapper.class).update(product);
                sqlSession.commit();
                updatedHouses++;
            }

        } catch (Throwable e) {
            sqlSession.rollback();
            LOG.error(e.getMessage());
        } finally {
            sqlSession.close();
            delete(fileName);
        }
        LOG.debug("Time taken to complete house properties for " + getApikey() + " with number of houses "
                + updatedHouses + " : " + ((System.currentTimeMillis() - startTime)) / 1000 + " seconds.");
    }

    @Override
    public void readDescriptions() {
        long startTime = System.currentTimeMillis();
        String altid;
        Product product;

        String fileName = "paxgenerator_house_descriptions_" + getApikey() + ".xml";
        int propertymanagerid = getPropertyManagerID(getApikey());

        final SqlSession sqlSession = RazorServer.openSession();
        try {
            long startParsing = System.currentTimeMillis();

            LOG.debug("Time taken to parse " + fileName + " : " + (System.currentTimeMillis() - startParsing)
                    + " milli seconds.");

            Element rootNode = document.getRootElement();
            List<Element> houses = rootNode.getChildren("offer", ns);
            int i = 0;
            StringBuilder sb;
            boolean needBreak = false;
            for (Element house : houses) {
                //try {
                i++;
                if (i < 1907) {
                    continue;
                }
                //               if (i % 30 == 0) {
                //                  Thread.sleep(36000);
                //               }
                //               if (i > 735) {
                //                  break;
                //               }

                System.out.println("!!!Product DESC i = " + i);
                System.out.println("!!!Product DESC i = " + i);
                System.out.println("!!!Product DESC i = " + i);
                altid = house.getAttributeValue("internal-id");
                product = PartnerService.getProduct(sqlSession, getAltpartyid(), altid, false);
                if (product == null) {
                    continue;
                }

                HashMap<String, String> texts = new HashMap<String, String>(); // Maps language to its text
                Element description = house.getChild("description", ns);
                if (description == null) {
                    continue;
                }
                String language = "RU";
                String text = description.getText();

                texts.put(language, text.length() <= IsPartner.TEXT_NOTES_LENGTH ? text
                        : text.substring(0, IsPartner.TEXT_NOTES_LENGTH));

                //if (!texts.containsKey(Language.EN) && RazorConfig.doTranslation()) {// must have an English description!
                if (!texts.containsKey(Language.EN)) {// must have an English description!
                    String englishTranslation;
                    for (String lang : texts.keySet()) {
                        // sleep for a while to meet google's rate limit
                        Thread.sleep(1200);
                        //System.out.println("TRY TO TRANSLATE: " + texts.get(lang) + ", " + lang + ", " + Language.EN);
                        englishTranslation = TextService.translate(texts.get(lang), lang, Language.EN);
                        if (StringUtils.isNotEmpty(englishTranslation)) {
                            texts.put(Language.EN, englishTranslation);
                            LOG.debug("English_Translation : " + texts.get(Language.EN));
                            break;
                        } else {
                            System.out.println("!!!TTRANSLATION FAILED!!!");
                        }
                        if (englishTranslation == null) {
                            needBreak = true;
                            break;
                        }
                    }
                }

                if (needBreak) {
                    break;
                }

                for (String lang : texts.keySet()) {
                    System.out.println("!!!updating: " + lang);
                    LOG.debug("language " + lang + " notes " + texts.get(lang));
                    product.setPublicText(new Text(product.getPublicId(), product.getPublicLabel(), Text.Type.Text,
                            new Date(), texts.get(lang), lang));
                    TextService.update(sqlSession, product.getTexts());
                }

                if (i > 0 && i % IsPartner.PRICE_BATCH_SIZE == 0) {
                    LOG.debug("Smart flush for description: " + i);
                    sqlSession.commit();
                }
                //} catch(Exception e) {
                //   e.printStackTrace();
                //}
            }
            sqlSession.commit();
        } catch (Throwable e) {
            e.printStackTrace();
            LOG.error(e.getMessage());
            sqlSession.rollback();
        } finally {
            sqlSession.close();
            delete(fileName);
        }
        LOG.debug("Time taken to complete product descriptions for " + getApikey() + " : "
                + ((System.currentTimeMillis() - startTime)) / 1000 + " seconds.");
    }

    public void incremenalImages() {
        final SqlSession sqlSession = RazorServer.openSession();
        long startTime = System.currentTimeMillis();
        Document document;
        String message = "Create Images started NextpaxAPIKey: " + getApikey();
        LOG.debug(message);
        Date version = new Date();

        String fileName = "paxgenerator_house_pictures_" + getApikey() + ".xml";
        try {
            // House attributes.
            // RelationService.load(sqlSession, Downloaded.PRODUCT_DOWNLOAD_DATE, getAltpartyid(), new Date().toString());
            SAXBuilder parser = new SAXBuilder();

            long startParsing = System.currentTimeMillis();
            document = parser.build(ftp(fileName));
            // document = parser.build(new File(System
            // .getProperty("user.home")
            // + File.separator
            // + "PMS"
            // + File.separator
            // + "nextpax"
            // + File.separator
            // + getApikey()
            // + File.separator + fileName));
            LOG.debug("Time taken to parse " + fileName + " : " + (System.currentTimeMillis() - startParsing)
                    + " milli seconds.");

            Element rootNode = document.getRootElement();
            String partner = rootNode.getChildText("Partner");
            List<Element> houses = rootNode.getChildren("Pictures");
            for (Element house : houses) {
                String altid = house.getChildText("HouseID");
                Product product = PartnerService.getProduct(sqlSession, getAltpartyid(), altid);
                if (product == null) {
                    continue;
                }
                String lastimage = sqlSession.getMapper(TextMapper.class)
                        .lastimage(NameId.Type.Product.name() + product.getId() + "-%");
                // if the images exist move to the next property images
                if (lastimage != null) {
                    continue;
                }

                ArrayList<NameId> images = new ArrayList<NameId>();
                List<Element> pictures = house.getChildren("Picture");
                for (Element picture : pictures) {
                    String name = picture.getChildText("Name");
                    // String size = picture.getChildText("Size");
                    String type = picture.getChildText("Type");
                    String title = getImageTitle(type);

                    images.add(new NameId(title,
                            IMAGE_URL + getBrandAbbreviation(partner) + "/" + altid + "/" + name));
                }
                LOG.debug("Total images uploading for the property " + product.getId() + ": " + images.size());

                UploadFileService.uploadImages(sqlSession, NameId.Type.Product, product.getId(), Language.EN,
                        images);
                sqlSession.commit();

                MonitorService.monitor(message, version);
            }
        } catch (Throwable e) {
            sqlSession.rollback();
            LOG.error(e.getMessage());
        } finally {
            sqlSession.close();
            delete(fileName);
        }
        long endTime = System.currentTimeMillis();
        LOG.debug("Total time taken for createImage execution " + getApikey() + " : " + (endTime - startTime) / 1000
                + " seconds.");
    }

    @Override
    public void readImages() {
        System.out.println("Yandex. Start reading images");
        final SqlSession sqlSession = RazorServer.openSession();
        String message = "Read Images";
        LOG.debug(message);
        Date version = new Date();
        try {

            Element rootNode = document.getRootElement();
            List<Element> houses = rootNode.getChildren("offer", ns);
            System.out.println("Number of properties " + houses.size());
            int j = 0;
            for (Element house : houses) {
                j++;
                System.out.println("Product images: " + j);
                String altid = house.getAttributeValue("internal-id");
                Product product = PartnerService.getProduct(sqlSession, getAltpartyid(), altid);
                if (product == null) {
                    continue;
                }
                //ArrayList<NameId> images = new ArrayList<NameId>();
                List<Element> images = house.getChildren("image", ns);
                System.out.println("Number of images " + images.size());
                int i = 1;
                for (Element imageElement : images) {
                    String name = product.getName();
                    String url = imageElement.getText();
                    System.out.println("Image name: " + name + ", url: " + url);

                    net.cbtltd.shared.Image image = new net.cbtltd.shared.Image();
                    image.setName(name);
                    image.setUrl(url);
                    image.setLanguage(Language.RU);
                    image.setType(Image.Type.Linked);
                    image.setStandard(true);
                    image.setProductId(Integer.parseInt(product.getId()));
                    image.setNotes(name);
                    image.setSort(i++);
                    image.setState("Created");

                    List<String> idList = sqlSession.getMapper(ImageMapper.class).imageidsbyurl(image);
                    if (idList != null && idList.size() > 0) {
                        image.setId(idList.get(0));
                        sqlSession.getMapper(ImageMapper.class).update(image);
                    } else {
                        sqlSession.getMapper(ImageMapper.class).create(image);
                    }

                    //images.add(new NameId(name, url));
                }
                //LOG.debug("Total images uploading for the property " + product.getId() + ": " + images.size());
                //UploadFileService.uploadImages(sqlSession, NameId.Type.Product, product.getId(), Language.EN, images);

                sqlSession.commit();
                MonitorService.monitor(message, version);
            }
        } catch (Throwable e) {
            sqlSession.rollback();
            e.printStackTrace();
            LOG.error(e.getMessage());
        } finally {
            sqlSession.close();
        }
        long endTime = System.currentTimeMillis();
        LOG.debug("Total time taken for readImage execution " + getApikey() + " : " + (endTime - startTime) / 1000
                + " seconds.");
    }

    public Element downloadImages(String rootFolder) {
        long startTime = System.currentTimeMillis();
        String message = "Download Images started NextpaxAPIKey: " + getApikey();
        LOG.debug(message);
        Date version = new Date();
        Document document;

        String fileName = "paxgenerator_house_pictures_" + getApikey() + ".xml";
        Element rootNode = null;
        try {
            // House attributes.
            long startParsing = System.currentTimeMillis();
            SAXBuilder parser = new SAXBuilder();
            // document = parser.build(new File(System
            // .getProperty("user.home")
            // + File.separator
            // + "PMS"
            // + File.separator
            // + "nextpax"
            // + File.separator
            // + getApikey()
            // + File.separator + fileName));
            document = parser.build(ftp(fileName));
            LOG.debug("Time taken to parse " + fileName + " : " + (System.currentTimeMillis() - startParsing)
                    + " milli seconds.");

            rootNode = document.getRootElement();
            String partner = rootNode.getChildText("Partner");
            List<Element> houses = rootNode.getChildren("Pictures");

            for (Element house : houses) {
                String altid = house.getChildText("HouseID");
                ArrayList<NameId> images = new ArrayList<NameId>();
                List<Element> pictures = house.getChildren("Picture");
                for (Element picture : pictures) {
                    String size = picture.getChildText("Size"); // need to check size, to prevent loading small images.
                    // n - normal, s - small.
                    if (size.equalsIgnoreCase("s")) {
                        continue; // we don't need small images
                    }
                    String name = picture.getChildText("Name");
                    String type = picture.getChildText("Type");
                    String title = getImageTitle(type);
                    String filename = getBrandAbbreviation(partner) + "/" + altid + "/" + name;
                    if (!new File(rootFolder + "/" + filename).exists()) {
                        images.add(new NameId(rootFolder + "/" + filename, IMAGE_URL + filename));
                    }
                }
                // multi threading image download and text creation
                // number of thread can be optimized by finding out available resources
                ExecutorService executor = Executors.newFixedThreadPool(25);
                Collection<Future<?>> futures = new LinkedList<Future<?>>();
                // download each image in it's own thread
                for (NameId image : images) {
                    try {
                        futures.add(
                                executor.submit(new A_Handler.ImageDownloadTask(image.getName(), image.getId())));
                    } catch (Throwable x) {
                        LOG.error("Bad or Absent Image URL: " + image.getId());
                        x.printStackTrace();
                    }
                }
                executor.shutdown();
                for (Future<?> future : futures) {
                    future.get();
                }
                LOG.debug("images " + images);
            }
        } catch (Throwable e) {
            LOG.error(e.getMessage());
        }
        long endTime = System.currentTimeMillis();
        LOG.debug("Total time taken for download image execution " + getApikey() + " : "
                + (endTime - startTime) / 1000 + " seconds.");
        return rootNode;
    }

    static class ImageDownloadTask extends Thread {
        String filename;
        String imageURL;

        public ImageDownloadTask(String filename, String imageURL) {
            this.filename = filename;
            this.imageURL = imageURL;
        }

        @Override
        public void run() {
            try {
                final long startTime = System.currentTimeMillis();
                URL url = new URL(imageURL.replace(" ", "%20"));
                LOG.error("Downloading file named: " + url);
                BufferedImage image = ImageIO.read(url);
                File file = new File(filename);
                file.getParentFile().mkdirs();
                // file.createNewFile();
                ImageIO.write(image, "jpeg", file);
                final long endTime = System.currentTimeMillis();
                LOG.error("Total time taken to download image " + url + " : " + (endTime - startTime)
                        + " miliseconds.");
            } catch (FileNotFoundException e) {
                LOG.error("Bad or Absent Image URL: " + imageURL + " " + e.getMessage());
            } catch (MalformedURLException e) {
                LOG.error("Bad or Absent Image URL: " + imageURL);
            } catch (IOException e) {
                LOG.error("Bad or Absent Image URL: " + imageURL);
            } catch (Exception e) {
                LOG.error("Error saving image to the filesystem: " + e.getMessage() + " Image URL: " + imageURL);
            }
        }
    }

    private static HashMap<String, Integer> PROPERTY_MANAGER_ID = null;

    private static final int getPropertyManagerID(String abbreviation) {
        abbreviation = abbreviation.toUpperCase();
        if (PROPERTY_MANAGER_ID == null) {
            PROPERTY_MANAGER_ID = new HashMap<String, Integer>();
            PROPERTY_MANAGER_ID.put("NS", 11);
            PROPERTY_MANAGER_ID.put("ER", 12);
            PROPERTY_MANAGER_ID.put("IH", 14);
            PROPERTY_MANAGER_ID.put("BN", 16);
            PROPERTY_MANAGER_ID.put("TU", 17);
            PROPERTY_MANAGER_ID.put("TT", 18);
            PROPERTY_MANAGER_ID.put("IC", 20);
            PROPERTY_MANAGER_ID.put("DC", 21);
            PROPERTY_MANAGER_ID.put("HH", 24);
            PROPERTY_MANAGER_ID.put("VC", 25);
            PROPERTY_MANAGER_ID.put("BS", 26);
            PROPERTY_MANAGER_ID.put("HA", 27);
            PROPERTY_MANAGER_ID.put("HB", 28);
            PROPERTY_MANAGER_ID.put("RP", 29);
            PROPERTY_MANAGER_ID.put("UT", 30);// no longer nextpax partner.
            PROPERTY_MANAGER_ID.put("GA", 71);
            PROPERTY_MANAGER_ID.put("NS", 25);
        }
        if (PROPERTY_MANAGER_ID.get(abbreviation) == null) {
            return -1;
        }
        return PROPERTY_MANAGER_ID.get(abbreviation);
    }

    private static HashMap<String, String> DESCRIPTION_TYPES = null;

    private static final String getDescriptionType(String language, String type) {
        if (DESCRIPTION_TYPES == null) {
            DESCRIPTION_TYPES = new HashMap<String, String>();
            // TODO:Translate to German
            DESCRIPTION_TYPES = new HashMap<String, String>();
            // TODO:Translate to German
            DESCRIPTION_TYPES.put("de-a", "Umwelt/Umgebung ");
            DESCRIPTION_TYPES.put("de-b", "Nebenkosten ");
            DESCRIPTION_TYPES.put("de-c", "Additional costs ");
            DESCRIPTION_TYPES.put("de-d", "Rabatte ");
            DESCRIPTION_TYPES.put("de-e", "Optionale Kosten ");
            DESCRIPTION_TYPES.put("de-h", "Haus ");
            DESCRIPTION_TYPES.put("de-i", "Interior ");
            DESCRIPTION_TYPES.put("de-l", "Ankunft tage ");
            DESCRIPTION_TYPES.put("de-m", "Mindestaufenthalt Lnge ");
            DESCRIPTION_TYPES.put("de-o", "ffnungszeiten");
            DESCRIPTION_TYPES.put("de-a", "Umwelt/Umgebung");
            DESCRIPTION_TYPES.put("de-b", "Nebenkosten");
            DESCRIPTION_TYPES.put("de-c", "Additional costs");
            DESCRIPTION_TYPES.put("de-d", "Rabatte");
            DESCRIPTION_TYPES.put("de-e", "Optionale Kosten");
            DESCRIPTION_TYPES.put("de-h", "Haus");
            DESCRIPTION_TYPES.put("de-i", "Interior");
            DESCRIPTION_TYPES.put("de-l", "Ankunft tage");
            DESCRIPTION_TYPES.put("de-m", "Mindestaufenthalt Lnge");
            DESCRIPTION_TYPES.put("de-o", "ffnungszeiten");
            DESCRIPTION_TYPES.put("de-p", "Preis in der Tabelle");
            DESCRIPTION_TYPES.put("de-r", "Remarks ");
            DESCRIPTION_TYPES.put("de-s", "Short introduction ");
            DESCRIPTION_TYPES.put("de-t", "Tips of the owner ");
            DESCRIPTION_TYPES.put("de-w", "Winter-Text ");
            DESCRIPTION_TYPES.put("de-z", "Winter-Text ");
            DESCRIPTION_TYPES.put("en-a", "Environment/surroundings ");
            DESCRIPTION_TYPES.put("en-b", "Distances ");
            DESCRIPTION_TYPES.put("en-c", "Additional costs ");
            DESCRIPTION_TYPES.put("en-d", "Discounts ");
            DESCRIPTION_TYPES.put("en-e", "Optional costs ");
            DESCRIPTION_TYPES.put("en-h", "House ");
            DESCRIPTION_TYPES.put("en-i", "Interior ");
            DESCRIPTION_TYPES.put("en-l", "Arrival days ");
            DESCRIPTION_TYPES.put("en-m", "Minimum stay length ");
            DESCRIPTION_TYPES.put("en-o", "Opening hours ");
            DESCRIPTION_TYPES.put("en-p", "Price table ");
            DESCRIPTION_TYPES.put("en-r", "Remarks ");
            DESCRIPTION_TYPES.put("en-s", "Short introduction ");
            DESCRIPTION_TYPES.put("en-t", "Tips of the owner ");
            DESCRIPTION_TYPES.put("en-w", "Winter text ");
            DESCRIPTION_TYPES.put("en-z", "Short winter text ");
            // TODO:Translate to Espanol
            DESCRIPTION_TYPES.put("es-a", "Environment/surroundings ");
            DESCRIPTION_TYPES.put("es-b", "Distances ");
            DESCRIPTION_TYPES.put("es-c", "Additional costs ");
            DESCRIPTION_TYPES.put("es-d", "Discounts ");
            DESCRIPTION_TYPES.put("es-e", "Optional costs ");
            DESCRIPTION_TYPES.put("es-h", "House ");
            DESCRIPTION_TYPES.put("es-i", "Interior ");
            DESCRIPTION_TYPES.put("es-l", "Arrival days ");
            DESCRIPTION_TYPES.put("es-m", "Minimum stay length ");
            DESCRIPTION_TYPES.put("es-o", "Opening hours ");
            DESCRIPTION_TYPES.put("es-p", "Price table ");
            DESCRIPTION_TYPES.put("es-r", "Remarks ");
            DESCRIPTION_TYPES.put("es-s", "Short introduction ");
            DESCRIPTION_TYPES.put("es-t", "Tips of the owner ");
            DESCRIPTION_TYPES.put("es-w", "Winter text ");
            DESCRIPTION_TYPES.put("es-z", "Short winter text ");
            // TODO:Translate to French
            DESCRIPTION_TYPES.put("fr-a", "Environment/surroundings ");
            DESCRIPTION_TYPES.put("fr-b", "Distances ");
            DESCRIPTION_TYPES.put("fr-c", "Additional costs ");
            DESCRIPTION_TYPES.put("fr-d", "Discounts ");
            DESCRIPTION_TYPES.put("fr-e", "Optional costs ");
            DESCRIPTION_TYPES.put("fr-h", "Maison ");
            DESCRIPTION_TYPES.put("fr-i", "Interior ");
            DESCRIPTION_TYPES.put("fr-l", "Arrival days ");
            DESCRIPTION_TYPES.put("fr-m", "Minimum stay length ");
            DESCRIPTION_TYPES.put("fr-o", "Opening hours ");
            DESCRIPTION_TYPES.put("fr-p", "Price table ");
            DESCRIPTION_TYPES.put("fr-r", "Remarks ");
            DESCRIPTION_TYPES.put("fr-s", "Short introduction ");
            DESCRIPTION_TYPES.put("fr-t", "Tips of the owner ");
            DESCRIPTION_TYPES.put("fr-w", "Winter text ");
            DESCRIPTION_TYPES.put("fr-z", "Short winter text ");
            // TODO:Translate to Dutch
            DESCRIPTION_TYPES.put("nl-a", "Environment/surroundings ");
            DESCRIPTION_TYPES.put("nl-b", "Distances ");
            DESCRIPTION_TYPES.put("nl-c", "Additional costs ");
            DESCRIPTION_TYPES.put("nl-d", "Discounts ");
            DESCRIPTION_TYPES.put("nl-e", "Optional costs ");
            DESCRIPTION_TYPES.put("nl-h", "House ");
            DESCRIPTION_TYPES.put("nl-i", "Interior ");
            DESCRIPTION_TYPES.put("nl-l", "Arrival days ");
            DESCRIPTION_TYPES.put("nl-m", "Minimum stay length ");
            DESCRIPTION_TYPES.put("nl-o", "Opening hours ");
            DESCRIPTION_TYPES.put("nl-p", "Price table ");
            DESCRIPTION_TYPES.put("nl-r", "Remarks ");
            DESCRIPTION_TYPES.put("nl-s", "Short introduction ");
            DESCRIPTION_TYPES.put("nl-t", "Tips of the owner ");
            DESCRIPTION_TYPES.put("nl-w", "Winter text ");
            DESCRIPTION_TYPES.put("nl-z", "Short winter text ");
        }
        String key = language.toLowerCase() + "-" + type.toLowerCase();
        // LOG.debug("key " + key + " value " + DESCRIPTION_TYPES.get(key));
        if (DESCRIPTION_TYPES.get(key) == null) {
            return "";
        }
        return DESCRIPTION_TYPES.get(key);
    }

    private static HashMap<String, String> ATTRIBUTES = null;

    private static HashMap<String, String> HOUSE_TYPES = null;

    /**
     * Attributes map.
     * 
     * @param attributes the attributes
     * @param attribute the attribute
     */
    static {
        if (ATTRIBUTES == null) {
            ATTRIBUTES = new HashMap<String, String>();
            ATTRIBUTES.put("A01", "FAC1"); // airconditionning
            ATTRIBUTES.put("A05", "FAC1"); // airconditionning living room
            ATTRIBUTES.put("A06", "FAC1"); // airconditionning bedroom
            ATTRIBUTES.put("B01", ""); // number of bathrooms...saved in product table
            ATTRIBUTES.put("B02", "ASZ"); // number of bedrooms. We can save up to 8 and anything greater than 8 will go into 9
            ATTRIBUTES.put("B08", "TRP1"); // Bicycles ('Y' = available) ?
            ATTRIBUTES.put("B11", "FAC2"); // Balcony (Y = available)
            ATTRIBUTES.put("B15", "RMA26"); // babycot
            ATTRIBUTES.put("C01", "SUI1"); // House is suitable for children ('Y' = applicable to this house)
            ATTRIBUTES.put("C07", ""); // Bicycle routes ('Y' = available)
            ATTRIBUTES.put("C08", ""); // Cooker (C = ceramic,
            // E = electric,
            // G = gas,
            // I = induction,
            // U = type unknown,
            // W = wood)
            ATTRIBUTES.put("C11", ""); // Coffee maker (E = espresso,
            // M = moka,
            // R = regular,
            // S = Senseo)
            ATTRIBUTES.put("C13", ""); // Child's bed(s)/ baby bed(s) on request
            ATTRIBUTES.put("C02", "HAC51"); // C02 Cleaning service ('Y' = available)
            ATTRIBUTES.put("C06", "RSN6"); // C06 Cross-country skiing ('Y' = available)
            ATTRIBUTES.put("D01", "RMA32"); // Dishwasher ('Y' = available)
            ATTRIBUTES.put("D02", ""); // Number of double beds
            ATTRIBUTES.put("D06", ""); // Douche (Y = available)
            ATTRIBUTES.put("D07", "RMA163"); // D07 DVD-playerr (Y = available)
            ATTRIBUTES.put("E01", ""); // Electric kettle
            ATTRIBUTES.put("F02", "RMA41"); // Fireplace or heater ('Y' = available)
            ATTRIBUTES.put("F04", "RMA88"); // Fridge ('Y' = available, F = with freezer, H = with hood)
            ATTRIBUTES.put("F06", ""); // Freezer (Y = available)
            ATTRIBUTES.put("G01", "HAC63"); // Garage or parking place ('Y' = available)
            ATTRIBUTES.put("G03", "RST134"); // Garden
            ATTRIBUTES.put("G04", ""); // Garden furniture (Y = available)
            // ATTRIBUTES.put("H03", "RSN16"); // H03 Horse riding (riding school) ('Y' = available)
            ATTRIBUTES.put("H03", "RST61"); // Horse riding (riding school) ('Y' = available)
            ATTRIBUTES.put("H40", "HAC242"); // Heating ('C' = central heating,
            // 'E' = electric,
            // 'F' = floor,
            // 'G' = gas,
            // H = hot air,
            // 'S' = stove, 'Y' = available)
            ATTRIBUTES.put("I02", "RMA54"); // Internet ('Y' = available,
            // A = ADSL,
            // C = cable,
            // I = ISDN,
            // S = satellite)
            ATTRIBUTES.put("I03", "RMA55"); // Iron (Y = available)
            ATTRIBUTES.put("I04", "RMA56"); // Ironing board (Y = available)
            // Map JAC_ATTRS = new HashMap<String, String>();
            // JAC_ATTRS.put("I")
            ATTRIBUTES.put("J01", "HAC55"); // Jacuzzi ('Y' = available,
            // I = indoor available,
            // O = outdoor available)
            // HAC55, RMA57
            ATTRIBUTES.put("L01", "RMA13"); // bathtub
            ATTRIBUTES.put("L02", "SEG8"); // House has a luxurious appearance ('Y' = applicable to this house)
            ATTRIBUTES.put("L04", ""); // Laundromat ('Y' = available,
            // 'C' = in the city,
            // 'P' = park facility,
            // S = service)
            ATTRIBUTES.put("M02", "RMA68"); // Microwave oven ('Y' = available)
            ATTRIBUTES.put("M03", "LOC25"); // Marina ('Y' = available)
            ATTRIBUTES.put("N01", "RMA74"); // House is for non-smokers ('Y' = applicable to this house)
            ATTRIBUTES.put("O01", "RMA77"); // Oven ('Y' = available, 'E' = electric, 'F' = fan, 'G' = gas, 'M' = microwave)
            ATTRIBUTES.put("P02", "SUI4"); // House is suitable for pets ('Y' = applicable to this house, 'R' = on request)
            ATTRIBUTES.put("P03", "RMA107"); // Telephone ('Y' = available)
            ATTRIBUTES.put("P04", "RST122"); // Indoor swimming pool ('Y' = available, 'P' = private, 'C' = communal)
            ATTRIBUTES.put("P05", "RST123"); // Outdoor swimming pool ('Y' = available, 'P' = private, 'C' = communal)
            ATTRIBUTES.put("P06", ""); // Surface area of house (in m 2 )
            ATTRIBUTES.put("P08", "RST74"); // Playground ('Y' = available)
            ATTRIBUTES.put("P09", "HAC253"); // P09 Private swimming pool, can be inside or outside ('Y' = available)
            ATTRIBUTES.put("P10", "HAC49"); // P10 Heated swimming pool, can be inside or outside (Y = available)
            ATTRIBUTES.put("P15", "HAC186"); // Number of parking places street side
            ATTRIBUTES.put("S01", "HAC79"); // Sauna ('Y' = available) REC61
            ATTRIBUTES.put("S02", ""); // Number of single beds
            ATTRIBUTES.put("S03", ""); // Number of sofas (Sofa-->CBF19
            ATTRIBUTES.put("S04", "RST90"); // Solarium ('Y' = available)
            ATTRIBUTES.put("S05", "RMA210"); // Satellite TV ('Y' = available)
            ATTRIBUTES.put("S06", "LOC16"); // House with sea view ('Y'= applicable to this house)
            ATTRIBUTES.put("S07", "RSN14"); // S07 House is well suited to go sailing ('Y' = applicable to this house)
            ATTRIBUTES.put("S10", "RSN15"); // S10 House is well suited to go surfing ('Y' = applicable to this house)
            ATTRIBUTES.put("S13", ""); // Situation: Detached
            ATTRIBUTES.put("S14", ""); // Situation: Semi detached
            ATTRIBUTES.put("S17", ""); // Situation: On an island
            ATTRIBUTES.put("S18", "LOC23"); // Situation: In the countryside
            ATTRIBUTES.put("S19", "LOC8"); // Situation: In the mountains > 1000 m.
            ATTRIBUTES.put("S20", ""); // Situation: Residential area
            ATTRIBUTES.put("S21", ""); // Situation: On holiday park
            ATTRIBUTES.put("T01", "RMA90"); // Television ('Y' = available)
            ATTRIBUTES.put("T02", "RMA7"); // Terrace ('Y' = available)
            ATTRIBUTES.put("T04", "RSP94"); // Private tennis court ('Y' = available)
            ATTRIBUTES.put("T05", "RMA140"); // Table tennis ('Y' = available)
            // RST117
            ATTRIBUTES.put("T07", ""); // Number of toilets --save this in product table
            ATTRIBUTES.put("T08", "STP2"); // ?Houses are located together (Y = applicable to his house)
            ATTRIBUTES.put("T09", "RSP94"); // Shared tennis court (Y = available)
            ATTRIBUTES.put("V03", ""); // Vacuum cleaner ('Y' = available)
            ATTRIBUTES.put("W01", "RMA31"); // Washing machine ('Y' = available)
            ATTRIBUTES.put("W03", "PHP24"); // House with access for wheelchairs ('Y' = applicable to this house)
            ATTRIBUTES.put("W05", ""); // Walking routes ('Y' = available)
            ATTRIBUTES.put("W06", "RST99"); // Water-skiing ('Y' = available)
            ATTRIBUTES.put("W07", "EQP55"); // WiFi ('Y' = available)
            ATTRIBUTES.put("W09", ""); // Available for longer stay in winter (Y = applicable to this house)
            ATTRIBUTES.put("W04", "FAC7"); // Whirlpool ('Y' = available)
            // ATTRIBUTES.put("bathandshower", "HAC263");
            ATTRIBUTES.put("bath", "HAC264");
            // ATTRIBUTES.put("bbq", "HAC118");
            // ATTRIBUTES.put("bikingplains", "RSN10");
            // ATTRIBUTES.put("breakfast", "HAC138");
            ATTRIBUTES.put("childrenplayground", "HAC193");
            // ATTRIBUTES.put("elevator", "HAC33");
            // ATTRIBUTES.put("fitness", "RSN12");
            // ATTRIBUTES.put("golfing", "RSN5");
            // ATTRIBUTES.put("hikingmountains", "RSN10");
            // ATTRIBUTES.put("hikingplains", "RSN10");
            // ATTRIBUTES.put("icerink", "RST84");
            // ATTRIBUTES.put("massage", "RSN12");
            // ATTRIBUTES.put("mountainbike", "RSP10");
            ATTRIBUTES.put("parkingprivate", "HAC63");
            ATTRIBUTES.put("parkingcovered", "HAC63");
            ATTRIBUTES.put("pool", "HAC71");
            ATTRIBUTES.put("All pets", "PET7");
            // ATTRIBUTES.put("poolindor", "HAC54");
            // ATTRIBUTES.put("poolchildren", "HAC48");
            // ATTRIBUTES.put("shower", "HAC265");
            ATTRIBUTES.put("ski", "ACC45");
            ATTRIBUTES.put("skiaera", "ACC45");
            // ATTRIBUTES.put("snowboard", "RSN6");
            ATTRIBUTES.put("tennis", "RST94"); // RSN17
            // ATTRIBUTES.put("terrace", "FAC2");
            // ATTRIBUTES.put("themepark", "RSN2");
            // ATTRIBUTES.put("wlan", "HAC221");
            // ATTRIBUTES.put("winterwalking", "RSN6");
            // ATTRIBUTES.put("water", "BEV20");
            ATTRIBUTES.put("1star", "GRD1");
            ATTRIBUTES.put("2star", "GRD2");
            ATTRIBUTES.put("3star", "GRD3");
            ATTRIBUTES.put("4star", "GRD4");
            ATTRIBUTES.put("5star", "GRD5");
        }
        if (HOUSE_TYPES == null) {
            HOUSE_TYPES = new HashMap<String, String>();
            HOUSE_TYPES.put("ALB", "PCT19");
            HOUSE_TYPES.put("APO", "PCT3, PCT20");
            HOUSE_TYPES.put("APP", "PCT3");
            HOUSE_TYPES.put("BNG", "PCT5");
            HOUSE_TYPES.put("BRY", "PCT15");
            HOUSE_TYPES.put("CAM", "PCT6");
            HOUSE_TYPES.put("CAR", "");
            HOUSE_TYPES.put("CHA", "PCT7");
            HOUSE_TYPES.put("CPR", "");
            HOUSE_TYPES.put("CRU", "PCT12");
            HOUSE_TYPES.put("EST", "PCT21");
            HOUSE_TYPES.put("GHF", "PCT21");
            HOUSE_TYPES.put("GUE", "PCT16");
            HOUSE_TYPES.put("HOS", "PCT19");
            HOUSE_TYPES.put("HOT", "PCT20");
            HOUSE_TYPES.put("HUI", "PCT34");
            HOUSE_TYPES.put("KAS", "PCT37");
            HOUSE_TYPES.put("MAI", "PCT34");
            HOUSE_TYPES.put("MOT", "PCT27");
            HOUSE_TYPES.put("PEN", "");
            HOUSE_TYPES.put("POU", "PCT21");
            HOUSE_TYPES.put("RES", "");
            HOUSE_TYPES.put("SCH", "PCT44");
            HOUSE_TYPES.put("TNT", "PCT33");
            HOUSE_TYPES.put("VIL", "PCT35");
            HOUSE_TYPES.put("WNG", "PCT34");
        }
    }

    // canel old reservations that do not have a reservation.altid.
    private void cancelOldReservations(SqlSession sqlSession, Date version) {
        // sqlSession = RazorServer.openSession();
        Reservation reservation = new Reservation();
        reservation.setVersion(version);
        reservation.setAltpartyid(getAltpartyid());
        sqlSession.getMapper(ReservationMapper.class).cancelversionbypartyid(reservation);

        sqlSession.commit();
    }

    private void resetStartTime() {
        startTime = System.currentTimeMillis();
    }

    private long getStartTime() {
        return startTime;
    }

    @Override
    public synchronized void readSchedule() {
        LOG.debug("Yandex readSchedule() key: " + this.getApikey() + "_started");
        Scanner sc = null;
        Date version = new Date();
        String line = "";
        String message = "readSchedule";
        String altid;
        String periodid;
        String startdate;
        String enddate;
        Double length;
        String lastminute;
        String rentprice;
        String bookingcosts;
        String discount;
        String othercosts;
        String totalprice;
        String discountcode;
        String recordhash;
        String[] houseinformation;

        Product product = null;

        String partyId = getAltpartyid();

        boolean firsttime = true;
        long startTime = System.currentTimeMillis();

        LOG.debug(message);
        final SqlSession sqlSession = RazorServer.openSession();
        try {
            SortedSet<DateTime> availableDates = new TreeSet<DateTime>();
            List<Price> prices = new ArrayList<Price>();
            long startTimeForProductProcessing = 0;
            int i = 0;

            Element rootNode = document.getRootElement();
            List<Element> houses = rootNode.getChildren("offer", ns);
            for (Element house : houses) {

                altid = house.getAttributeValue("internal-id");
                product = PartnerService.getProduct(sqlSession, partyId, altid);
                System.out.println("PRODUCT ID: " + product.getId());

                Element ratePeriods = house.getChild("rateperiods", ns);
                List<Element> ratePeriodList = ratePeriods.getChildren("rateperiod", ns);
                System.out.println("ratePeriodList size = " + ratePeriodList.size());
                for (Element ratePeriod : ratePeriodList) {
                    startdate = ratePeriod.getChildText("startdate", ns);
                    enddate = ratePeriod.getChildText("enddate", ns);
                    System.out.println("startdate = " + startdate);
                    System.out.println("enddate = " + enddate);

                    addToAvailableDates(availableDates, startdate, enddate);
                    createSchedule(availableDates, product, version, sqlSession);
                }
            }
            /*
            String currenthouse = "";
            while (sc.hasNext()) {
               line = sc.nextLine();
               if (line.isEmpty()) {
                  continue;
               }
               houseinformation = line.split("\\|");
                
               if (firsttime) {
                  currenthouse = houseinformation[0];
                  product = sqlSession.getMapper(ProductMapper.class).altread(new NameId(partyId, currenthouse));
                  if (product == null) {
              continue;
                  }
                  firsttime = false;
                  // product = PartnerService.getProduct(sqlSession, partyId, currenthouse); // check for null
                  startTimeForProductProcessing = System.currentTimeMillis();
               }
                
               altid = houseinformation[0];
               periodid = houseinformation[1];
               startdate = houseinformation[2];
               enddate = houseinformation[3];
               length = Double.valueOf(houseinformation[4]);
               lastminute = houseinformation[5];
               rentprice = houseinformation[6];
               bookingcosts = houseinformation[7];
               discount = houseinformation[8];
               othercosts = houseinformation[9];
               totalprice = houseinformation[10];
               discountcode = houseinformation[11];
               recordhash = houseinformation[12];
                
               // price table
               Price price = new Price();
               price.setAltid(periodid);
               price.setPartyid(getAltpartyid());
               price.setEntitytype(NameId.Type.Product.name());
               price.setEntityid(product.getId());
               price.setCurrency(Currency.Code.EUR.name());
               price.setQuantity(length);
               price.setUnit(Unit.DAY);
               price.setName(Price.RACK_RATE);
               price.setType(NameId.Type.Reservation.name());
               price.setDate(DF.parse(startdate));
               price.setTodate(DF.parse(enddate));
                
               net.cbtltd.shared.Price exists = sqlSession.getMapper(PriceMapper.class).existsAltID(price);
                
               price.setFactor(1.0);
               price.setOrganizationid(getAltpartyid());
               price.setRule(getDayOfWeek(DF.parse(startdate)));
               price.setAvailable(1);
               price.setState(Price.CREATED);
               double unitprice = Double.valueOf(totalprice) / length; // what is this ?
               price.setValue(NameId.round(Double.valueOf(totalprice) / length));
               price.setMinimum(Double.valueOf(totalprice));
               price.setMinStay(length.intValue());
               price.setVersion(version);
                
               price.setEntityid(product.getId());
               if (exists != null) {
                  //add price into array and update it after
                  // sqlSession.getMapper(PriceMapper.class).create(price);
                      
                  // check if there is reservation for this price.
                  // if reservation is created and we still get the price,
                  // we need to cancel the reservation
                  Reservation action = new Reservation();
                  action.setProductid(product.getId());
                  action.setFromdate(price.getDate());
                  action.setTodate(price.getTodate());
                  action = sqlSession.getMapper(ReservationMapper.class).collides(action);
                  if (action != null && StringUtils.isNotBlank(action.getAltid())) {
              // cancel this reservation
              PartnerService.cancelReservation(sqlSession, action);
                  }
                  price.setId(exists.getId());
                  // sqlSession.getMapper(PriceMapper.class).update(price);
               }
               prices.add(price);
                
               // when we come across a new house will create reservations for
               // the blocked dates for the previous house.
               // create a map of available dates
               // iterate through prices and check off the dates from the
               // collection of month dates and use the rest of the dates
               // to create the reservation
               if (currenthouse.compareTo(altid) != 0 || !sc.hasNext()) {
                  if (!sc.hasNext()) {
              addToAvailableDates(availableDates, startdate, enddate);
                  }
                
                  createSchedule(availableDates, product, version, sqlSession);
                  // insert list of prices
                  sqlSession.getMapper(PriceMapper.class).insertList(prices);
                  // clear list
                  prices.clear();
                  sqlSession.commit();
                      
                  LOG.debug("Time taken for Product Process " + currenthouse + " : "
                 + (System.currentTimeMillis() - startTimeForProductProcessing));
                
                  // now cancel price for existing property that we did not process in this run.
                  sqlSession.getMapper(PriceMapper.class).cancelversion(price);
                
                  // reset fields
                  // create a new set for the next home
                  currenthouse = altid;
                  availableDates = new TreeSet<DateTime>();
                  // product = PartnerService.getProduct(sqlSession, partyId, currenthouse);
                  product = sqlSession.getMapper(ProductMapper.class).altread(new NameId(partyId, currenthouse));
                  startTimeForProductProcessing = System.currentTimeMillis();
               }
                
               if (sc.hasNext()) {
                  addToAvailableDates(availableDates, startdate, enddate);
               }
                
            }*/
            sqlSession.commit();

            // Cancel old reservations.
            resetStartTime();
            cancelOldReservations(sqlSession, version);
            LOG.debug("Canceled old reservations: " + (System.currentTimeMillis() - getStartTime()));
            sqlSession.commit();

        } catch (Throwable x) {
            sqlSession.rollback();
            LOG.error(x.getMessage());
        } finally {
            if (sc != null) {
                try {
                    sc.close();
                    sqlSession.close();
                } catch (Exception e) {
                    LOG.error(e.getMessage());
                }
            }
        }
        long endTime = System.currentTimeMillis();
        LOG.debug("NextPax readSchedule() for key: " + this.getApikey() + " done." + " Time: "
                + (endTime - startTime));
        MonitorService.monitor(message, version);
    }

    // Monday = 1 - Sunday = 7.
    public String getDayOfWeek(Date startdate) {
        String checkinday = Rule.AnyCheckIn.name();
        switch (new DateTime(startdate).getDayOfWeek()) {
        case 1:
            checkinday = Rule.MonCheckIn.name();
            break;
        case 2:
            checkinday = Rule.TueCheckIn.name();
            break;
        case 3:
            checkinday = Rule.WedCheckIn.name();
            break;
        case 4:
            checkinday = Rule.ThuCheckIn.name();
            break;
        case 5:
            checkinday = Rule.FriCheckIn.name();
            break;
        case 6:
            checkinday = Rule.SatCheckIn.name();
            break;
        case 7:
            checkinday = Rule.SunCheckIn.name();
            break;
        default:
            LOG.error("error in parsing DayOfWeek: " + startdate);
        }

        return checkinday;
    }

    private void addToAvailableDates(SortedSet<DateTime> availableDates, String startdate, String enddate)
            throws ParseException {
        int daysBetween = Days.daysBetween(new DateTime(DF.parse(startdate)), new DateTime(DF.parse(enddate)))
                .getDays();
        DateTime startDate = new DateTime(DF.parse(startdate));
        for (int i = 0; i <= daysBetween; i++) {
            availableDates.add(startDate.withFieldAdded(DurationFieldType.days(), i));
        }
    }

    private void createSchedule(SortedSet<DateTime> availableDates, Product product, Date version,
            SqlSession sqlSession) {
        DateTime currentDate = new DateTime(version).withTime(0, 0, 0, 0);

        // create reservation if current date is less than the first date in the available dates set
        DateTime firstAvailableDate = availableDates.first();
        System.out.println("firstAvailableDate = " + firstAvailableDate);
        int daysBetween = Days.daysBetween(currentDate, availableDates.first()).getDays();
        System.out.println("createSchedule daysBetween: " + daysBetween);
        System.out.println("daysBetween = " + currentDate + ",  " + availableDates.first());
        if (daysBetween > 1) {
            PartnerService.createSchedule(sqlSession, product, currentDate.toDate(),
                    firstAvailableDate.withFieldAdded(DurationFieldType.days(), -1).toDate(), version);
        }

        DateTime fromDate = firstAvailableDate;

        boolean first = true;
        System.out.println("availableDates size = " + availableDates.size());
        for (DateTime toDate : availableDates) {
            if (first) {
                first = false;
                continue;
            }
            daysBetween = Days.daysBetween(fromDate, toDate).getDays();
            if (daysBetween > 1 && toDate.isAfterNow()) {
                System.out.println("createSchedule availableDates daysBetween: " + daysBetween);
                PartnerService.createSchedule(sqlSession, product,
                        fromDate.withFieldAdded(DurationFieldType.days(), 1).toDate(),
                        toDate.withFieldAdded(DurationFieldType.days(), -1).toDate(), version);
            }
            fromDate = toDate;
        }
    }

    /**
     * Read special accommodation prices.
     */
    @Override
    public void readSpecials() {
        throw new ServiceException(Error.service_absent, "NextPax readSpecials()");
    }

    private static HashMap<String, String> BRAND_ABBREVIATON = null;

    private static final String getBrandAbbreviation(String brandname) {
        if (BRAND_ABBREVIATON == null) {
            BRAND_ABBREVIATON = new HashMap<String, String>();
            BRAND_ABBREVIATON.put("BUNGALOWNET", "bn");
            BRAND_ABBREVIATON.put("CENTERPARCS", "cp");
            BRAND_ABBREVIATON.put("CLICKANDRENT", "bs");
            BRAND_ABBREVIATON.put("CUENDET", "cu");
            BRAND_ABBREVIATON.put("DANCENTER", "dc");
            BRAND_ABBREVIATON.put("DANSOMMER", "ds");
            BRAND_ABBREVIATON.put("BELVILLA", "er");
            BRAND_ABBREVIATON.put("FERATEL", "fe");
            BRAND_ABBREVIATON.put("GRANALACANT", "ga");
            BRAND_ABBREVIATON.put("HAPPYHOME", "ha");
            BRAND_ABBREVIATON.put("HOGENBOOM", "hb");
            BRAND_ABBREVIATON.put("HOLIDAYHOME", "hh");
            BRAND_ABBREVIATON.put("INTERCHALET", "ic");
            BRAND_ABBREVIATON.put("INTERHOME", "ih");
            BRAND_ABBREVIATON.put("JUSTFRANCE", "jf");
            BRAND_ABBREVIATON.put("JULESVILLAS", "jv");
            BRAND_ABBREVIATON.put("NOVASOL", "ns");
            BRAND_ABBREVIATON.put("ROOMPOT", "rp");
            BRAND_ABBREVIATON.put("SOLOGSTRAND", "sg");
            BRAND_ABBREVIATON.put("SUNPARCS", "sp");
            BRAND_ABBREVIATON.put("TOPICTRAVEL", "tt");
            BRAND_ABBREVIATON.put("TUI", "tu");
            BRAND_ABBREVIATON.put("UPHILLTRAVEL", "ut");
            BRAND_ABBREVIATON.put("VACASOL", "vc");
            BRAND_ABBREVIATON.put("YANDEX", "ya");
        }
        return BRAND_ABBREVIATON.get(brandname.toUpperCase());
    }

    private static HashMap<String, String> HOUSE_PROPERTY = null;

    // see appendix D for more information.
    private static final String getHouseProperty(String houseproperty) {
        if (HOUSE_PROPERTY == null) {
            HOUSE_PROPERTY = new HashMap<String, String>();
            HOUSE_PROPERTY.put("B01", "Number of bathrooms");
            HOUSE_PROPERTY.put("B02", "Number of bedrooms");
            HOUSE_PROPERTY.put("A01", "Air conditioning");
        }
        return HOUSE_PROPERTY.get(houseproperty);
    }

    private static HashMap<String, String> IMAGE_TYPES = null;

    /**
     * Gets the image.
     * 
     * @param value the image code.
     * @return the image description.
     */
    // TODO: put for other lanauges beside english.
    private static String getImageTitle(String value) {
        if (IMAGE_TYPES == null) {
            IMAGE_TYPES = new HashMap<String, String>();
            IMAGE_TYPES.put("a", "Exterior house");
            IMAGE_TYPES.put("c", "Living room");
            IMAGE_TYPES.put("d", "Living/dining room");
            IMAGE_TYPES.put("e", "Dining room");
            IMAGE_TYPES.put("f", "Map");
            IMAGE_TYPES.put("g", "Fireplace room");
            IMAGE_TYPES.put("h", "House");
            IMAGE_TYPES.put("i", "Kitchen diner");
            IMAGE_TYPES.put("j", "Kitchen");
            IMAGE_TYPES.put("k", "Bedroom");
            IMAGE_TYPES.put("l", "Bathroom");
            IMAGE_TYPES.put("m", "Model");
            IMAGE_TYPES.put("n", "Sauna");
            IMAGE_TYPES.put("o", "Whirlpool");
            IMAGE_TYPES.put("p", "Indoor swimming pool");
            IMAGE_TYPES.put("q", "Terrace");
            IMAGE_TYPES.put("r", "Outside");
            IMAGE_TYPES.put("s", "Summer");
            IMAGE_TYPES.put("t", "Fishing");
            IMAGE_TYPES.put("u", "Other");
            IMAGE_TYPES.put("w", "Winter");
        }
        if (value == null || IMAGE_TYPES.get(value.toLowerCase()) == null) {
            return null;
        } else {
            return IMAGE_TYPES.get(value.toLowerCase());
        }
    }

    private String getXMLTestAttrubuiteStatus() {
        return RazorConfig.isProduction() ? "nee" : "ja";
    }

    public String formatCreditCardType(CreditCardType creditCardType) {
        if (creditCardType.name().equals(CreditCardType.VISA.name()))
            return CreditCardType.VISA.name().toLowerCase();
        return "mast";
    }

    public boolean aceptedCreditCardTypes(CreditCardType creditCardType) {// maybe allow for amercain express?
        return creditCardType.name().equals(CreditCardType.MASTER_CARD.name())
                || creditCardType.name().equals(CreditCardType.VISA.name());
    }

    // information :
    // https://docs.google.com/spreadsheet/ccc?key=0ArV0twP1-FUedHRJWDg0UXRTUVdLSHpFdGNFLXFLV3c&usp=drive_web#gid=0
    private boolean emailPayment(int nextpaxpartnerid) {
        return nextpaxpartnerid == 11 || nextpaxpartnerid == 12 || nextpaxpartnerid == 18 || nextpaxpartnerid == 21
                || nextpaxpartnerid == 24 || nextpaxpartnerid == 27 || nextpaxpartnerid == 28
                || nextpaxpartnerid == 71 || nextpaxpartnerid == 29 || nextpaxpartnerid == 26;
    }

    private boolean bankTransferOnly(int nextpaxpartnerid) // Confirming with Robert to add 21.
    {
        return (nextpaxpartnerid == 11 || nextpaxpartnerid == 18 || nextpaxpartnerid == 21 || nextpaxpartnerid == 24
                || nextpaxpartnerid == 27 || nextpaxpartnerid == 28 || nextpaxpartnerid == 71
                || nextpaxpartnerid == 29 || nextpaxpartnerid == 26);
    }

    private boolean creditCardOnly(int nextpaxpartnerid) {
        return nextpaxpartnerid == 20 || nextpaxpartnerid == 17;
    }

    /**
     * {@inheritDoc}
     */

    @Override
    public Map<String, String> createReservationAndPayment(SqlSession sqlSession, Reservation reservation,
            CreditCard creditCard) {
        LOG.error("Using Configuration: " + RazorConfig.getEnvironmentId());
        long timestamp = new Date().getTime();
        String message = "createReservationAndPayment " + reservation.getId();
        LOG.debug(message);
        String rq;
        String rs;

        Map<String, String> result = new HashMap<String, String>();
        StringBuilder sb = new StringBuilder();
        String senderSessionID = timestamp + "bookingnetS";
        String receiverSessionID = timestamp + "bookingnetR";
        String creditCardInormation;
        String fakeBankAccountInformation;
        try {
            if (reservation.notActive()) {
                throw new ServiceException(Error.reservation_state,
                        reservation.getId() + " state " + reservation.getState());
            }

            Product product = sqlSession.getMapper(ProductMapper.class).read(reservation.getProductid());
            if (product == null) {
                throw new ServiceException(Error.product_id, reservation.getProductid());
            }
            if (reservation.noAgentid()) {
                throw new ServiceException(Error.reservation_agentid);
            }
            Party agent = sqlSession.getMapper(PartyMapper.class).read(reservation.getAgentid());
            if (agent == null) {
                throw new ServiceException(Error.party_id, reservation.getAgentid());
            }
            if (reservation.noCustomerid()) {
                reservation.setCustomerid(Party.NO_ACTOR);
            }
            Party customer = sqlSession.getMapper(PartyMapper.class).read(reservation.getCustomerid());
            if (customer == null) {
                throw new ServiceException(Error.reservation_customerid, reservation.getCustomerid());
            }

            final long startTime = System.currentTimeMillis();
            Price price = sqlSession.getMapper(PriceMapper.class).altidfromdate(reservation);
            final long endTime = System.currentTimeMillis();

            System.out.println("Total execution time: " + (endTime - startTime) / 1000.00);

            if (price == null || (!price.hasAltid())) {
                throw new ServiceException(Error.price_data, reservation.getCustomerid());
            }
            //if(bankTransferOnly(nextpaxpartnerid)) {throw new ServiceException(Error.bank_transfer,product.getAltpartyid());}
            if (!aceptedCreditCardTypes(creditCard.getType())) {
                throw new ServiceException(Error.card_type, creditCard.getType().name());
            }

            int nextpaxpartnerid = Integer.parseInt(product.getAltSupplierId());
            // if(bankTransferOnly(nextpaxpartnerid)) {throw new ServiceException(Error.bank_transfer,product.getAltpartyid());}
            if (!aceptedCreditCardTypes(creditCard.getType())) {
                throw new ServiceException(Error.card_type, creditCard.getType().name());
            }

            // sequence SellRequest.xml -> AssignRequest.xml -> BookRequest.xml
            // SellRequest.xml
            sb.append("<?xml version='1.0' ?>");
            sb.append("<TravelMessage VersionID='1.8N'>");
            sb.append("  <Control Language='NL' Test='nee'>");// + getXMLTestAttrubuiteStatus() + "'>");
            sb.append("    <SenderSessionID>" + senderSessionID + "</SenderSessionID>");
            sb.append("    <ReceiverSessionID>" + receiverSessionID + "</ReceiverSessionID>");
            sb.append("    <Date>" + DF.format(new Date()) + "</Date>");
            sb.append("    <Time Reliability='zeker'>" + TF.format(new Date()) + "</Time>");
            sb.append("    <MessageSequence>1</MessageSequence>");
            sb.append("    <SenderID>" + SENDERID + "</SenderID>");
            sb.append("    <ReceiverID>NPS001</ReceiverID>");// Default \91NPS001\92
            sb.append("    <RequestID>SellRequest</RequestID>");
            sb.append("    <ResponseID>SellResponse</ResponseID>");
            sb.append("  </Control>");
            sb.append("  <TRequest>");
            sb.append("    <SellRequest>");
            sb.append("      <PackageDetails>");
            sb.append("        <PackageID>" + price.getAltid() + "</PackageID>");
            sb.append("        <NumberOfAdults>" + reservation.getAdult() + "</NumberOfAdults>");
            sb.append("        <NumberOfChildren>" + reservation.getChild() + "</NumberOfChildren>");
            sb.append("        <NumberOfBabies>0</NumberOfBabies>");
            sb.append("        <DepartureDate>" + DF.format(reservation.getFromdate()) + "</DepartureDate>");
            sb.append("        <Duration DurationType='dagen'>" + reservation.getDuration(Time.DAY).intValue()
                    + "</Duration>");
            sb.append("      </PackageDetails>");
            sb.append("    </SellRequest>");
            sb.append("  </TRequest>");
            sb.append("</TravelMessage>");
            rq = sb.toString();

            // reservation.
            // sequence SellRequest.xml -> AssignRequest -> BookRequest
            if (LOG.isDebugEnabled()) {
                LOG.debug("\nSellRequest rq: \n" + rq + "\n");
            }
            rs = getConnection(rq);
            LOG.debug("\nSellRequest rs: \n" + rs + "\n");

            // AssignResuest.xml
            sb = new StringBuilder();
            sb.append("<?xml version='1.0' ?>");
            sb.append("<TravelMessage VersionID='1.8N'>");
            sb.append("  <Control Language='NL' Test='nee'>");// + getXMLTestAttrubuiteStatus() + "'>");
            sb.append("    <SenderSessionID>" + senderSessionID + "</SenderSessionID>");
            sb.append("    <ReceiverSessionID>" + receiverSessionID + "</ReceiverSessionID>");
            sb.append("    <Date>" + DF.format(new Date()) + "</Date>");
            sb.append("    <Time Reliability='zeker'>" + TF.format(new Date()) + "</Time>");
            sb.append("    <MessageSequence>1</MessageSequence>");
            sb.append("    <SenderID>" + SENDERID + "</SenderID>");
            sb.append("    <ReceiverID>NPS001</ReceiverID>");
            sb.append("    <RequestID>AssignRequest</RequestID>");
            sb.append("    <ResponseID>AssignResponse</ResponseID>");
            sb.append("  </Control>");
            sb.append("  <TRequest>");
            sb.append("    <AssignRequest>");
            sb.append("      <PaxDetails>");
            sb.append("        <PaxDescription>");
            sb.append("          <PaxID>P01</PaxID>");
            sb.append("          <Initials>" + customer.getFirstName().substring(0, 1) + "</Initials>");
            sb.append("          <Infix>''</Infix>");
            sb.append("          <Name>" + customer.getName() + "</Name>");
            sb.append("          <Gender>m</Gender>");
            sb.append("        </PaxDescription>");
            sb.append("        <HomeStay>");
            sb.append("          <Name>" + customer.getName() + "</Name>");
            sb.append("          <TelHome>" + customer.getDayphone() + "</TelHome>");
            sb.append("        </HomeStay>");
            sb.append("      </PaxDetails>");
            sb.append("      <PaxAssignment>");
            sb.append("        <AccoAssignment>");
            sb.append("          <AccommodationID>" + "A" + product.getAltid() + "</AccommodationID>");
            // <AccommodationID> 'A' + HouseID, e.g. 'A1712' if the XML contained <HouseID>1712</HouseID>.
            sb.append("          <ArrivalDate>" + DF.format(reservation.getFromdate()) + "</ArrivalDate>");
            sb.append("          <Duration DurationType='dagen'>" + reservation.getDuration(Time.DAY).intValue()
                    + "</Duration>");
            sb.append("          <UnitAssignment>");
            sb.append("            <UnitID>U01</UnitID>");
            sb.append("            <Quantity>1</Quantity>");
            sb.append("            <RoomAssignment>");
            sb.append("              <Sequence>1</Sequence>");
            sb.append("              <PaxID>P01</PaxID>");
            sb.append("            </RoomAssignment>");
            sb.append("          </UnitAssignment>");
            sb.append("        </AccoAssignment>");
            sb.append("      </PaxAssignment>");
            sb.append("    </AssignRequest>");
            sb.append("  </TRequest>");
            sb.append("</TravelMessage>");

            rq = sb.toString();
            LOG.debug("\nAssignRequest rq: \n" + rq + "\n");
            rs = getConnection(rq);
            LOG.debug("\nAssignRequest rs: \n" + rs + "\n");

            creditCardInormation = "          <BankAccount>creditcard;" + formatCreditCardType(creditCard.getType())
                    + ";" + creditCard.getNumber() + ";" + creditCard.getYear() + "-" + creditCard.getMonth() + ";"
                    + creditCard.getFirstName() + ";" + creditCard.getLastName() + ";"
                    + creditCard.getSecurityCode() + "</BankAccount>";
            fakeBankAccountInformation = "          <BankAccount>0000</BankAccount>";

            // /BookRequest.xml
            sb = new StringBuilder();
            sb.append("<?xml version='1.0' ?>");
            sb.append("<TravelMessage VersionID='1.8N'>");
            sb.append("  <Control Language='NL' Test='nee'>");// + getXMLTestAttrubuiteStatus() + "'>");
            sb.append("    <SenderSessionID>" + senderSessionID + "</SenderSessionID>");
            sb.append("    <ReceiverSessionID>" + receiverSessionID + "</ReceiverSessionID>");
            sb.append("    <Date>" + DF.format(new Date()) + "</Date>");
            sb.append("    <Time Reliability='zeker'>" + TF.format(new Date()) + "</Time>");
            sb.append("    <MessageSequence>1</MessageSequence>");
            sb.append("    <SenderID>" + SENDERID + "</SenderID>");
            sb.append("    <ReceiverID>NPS001</ReceiverID>");
            sb.append("    <RequestID>BookRequest</RequestID>");
            sb.append("    <ResponseID>BookResponse</ResponseID>");
            sb.append("  </Control>");
            sb.append("  <TRequest>");
            sb.append("    <BookRequest>");
            sb.append("      <PaxDetails>");
            sb.append("        <PaxDescription>");
            sb.append("          <PaxID>P01</PaxID>");
            sb.append("          <Initials>" + customer.getFirstName().substring(0, 1) + "</Initials>");
            sb.append("          <Infix>" + "de" + "</Infix>");
            sb.append("          <Name>" + customer.getFamilyName() + "</Name>");
            sb.append("          <Gender>m</Gender>");
            sb.append("        </PaxDescription>");
            sb.append("        <Contact>");
            sb.append("          <Initials>" + customer.getFirstName().substring(0, 1) + "</Initials>");
            sb.append("          <Name>" + customer.getFamilyName() + "</Name>");
            sb.append("          <Gender>m</Gender>");
            sb.append("          <Address>" + customer.getLocalAddress() + "</Address>");
            sb.append("          <Zipcode>" + customer.getPostalcode() + "</Zipcode>"); ///makse sure their is a value
            sb.append("          <Place>" + customer.getLocalAddress() + "</Place>");
            sb.append("          <Country>" + customer.getCountry() + "</Country>");
            sb.append("          <TelHome>" + customer.getDayphone() + "</TelHome>");
            sb.append("          <TelWork>" + customer.getDayphone() + "</TelWork>");
            sb.append("          <TelMobile>" + customer.getDayphone() + "</TelMobile>");
            sb.append("          <Email>" + customer.getEmailaddress() + "</Email>");
            sb.append(bankTransferOnly(nextpaxpartnerid) ? fakeBankAccountInformation : creditCardInormation);
            sb.append("        </Contact>");
            sb.append("        <HomeStay>");
            sb.append("          <Name>" + customer.getName() + "</Name>");
            sb.append("          <TelHome>" + customer.getDayphone() + "</TelHome>");
            sb.append("        </HomeStay>");
            sb.append("      </PaxDetails>");
            sb.append("      <PaxAssignment>");
            sb.append("        <AccoAssignment>");
            sb.append("          <AccommodationID>" + "A" + product.getAltid() + "</AccommodationID>");
            sb.append("          <ArrivalDate>" + DF.format(reservation.getFromdate()) + "</ArrivalDate>");
            sb.append("          <Duration DurationType='dagen'>" + reservation.getDuration(Time.DAY).intValue()
                    + "</Duration>");
            sb.append("          <UnitAssignment>");
            sb.append("            <UnitID>U01</UnitID>");
            sb.append("            <Quantity>1</Quantity>");
            sb.append("            <RoomAssignment>");
            sb.append("              <Sequence>1</Sequence>");
            sb.append("              <PaxID>P01</PaxID>");
            sb.append("            </RoomAssignment>");
            sb.append("          </UnitAssignment>");
            sb.append("        </AccoAssignment>");
            sb.append("      </PaxAssignment>");
            sb.append("    </BookRequest>");
            sb.append("  </TRequest>");
            sb.append("</TravelMessage>");

            rq = sb.toString();
            LOG.debug("\nBookRequest rq: \n" + rq + "\n");
            createBooking(rq, reservation, timestamp, result);
        } catch (Throwable x) {
            result.put(GatewayHandler.STATE, GatewayHandler.FAILED);
            reservation.setMessage(x.getMessage());
            reservation.setState(Reservation.State.Cancelled.name());
            LOG.error(x.getMessage());
        }
        sqlSession.getMapper(ReservationMapper.class).update(reservation);
        MonitorService.monitor(message, new Date(timestamp));

        return result;
    }

    private void createBooking(String rq, Reservation reservation, long timestamp, Map<String, String> result)
            throws Throwable {
        String rs = getConnection(rq);
        LOG.debug("\nBookResponse rs: \n" + rs + "\n");
        XPathFactory factory = XPathFactory.newInstance();
        XPath xpath = factory.newXPath();
        InputSource inputSource = new InputSource(new StringReader(rs.toString()));
        String bookID = (String) xpath.evaluate("//BookID", inputSource, XPathConstants.STRING);
        if (bookID.isEmpty()) {
            throw new ServiceException(Error.reservation_api, reservation.getId());
        } else {
            reservation.setAltid(bookID);
            reservation.setAltpartyid(getAltpartyid());
            reservation.setMessage(reservation.getMessage());
            reservation.setVersion(new Date(timestamp));
            reservation.setState(Reservation.State.Confirmed.name());
            result.put(GatewayHandler.STATE, GatewayHandler.ACCEPTED);
        }
    }

    @Override
    public ReservationPrice readPrice(SqlSession sqlSession, Reservation reservation, String productAltId,
            String currency) {
        ReservationPrice reservationPrice = new ReservationPrice();
        //don't need to include Total Quote into quote details
        QuoteDetail qd = new QuoteDetail();
        List<QuoteDetail> quoteDetails = new LinkedList<QuoteDetail>();

        reservation.setCurrency(currency);
        readPrice(sqlSession, reservation, productAltId);

        if (reservation.getPrice() <= 0) {
            throw new ServiceException(Error.product_not_available/*, reservation.getProductFromToDate()*/);
        }

        qd.setDescription("Total quote");
        qd.setAmount(reservation.getPrice() + "");
        qd.setIncluded(true);
        qd.setCurrency(currency);
        reservation.setQuote(reservation.getPrice());
        quoteDetails.add(qd);
        reservationPrice.setQuoteDetails(quoteDetails);
        reservationPrice.setCurrency(currency);
        reservationPrice.setTotal(reservation.getPrice()); // TODO : set quotes values instead of price
        reservationPrice.setPrice(reservation.getPrice());
        // LOG.debug("Isaac : Quote()"+reservation.getQuote());

        return reservationPrice;
    }

    private static Reservation readPrice(SqlSession sqlSession, Reservation reservation, String productAltId) {
        StringBuilder sb = new StringBuilder();
        Date now = new Date();
        long time = now.getTime();
        String SenderSessionID = time + "bookingnetS";
        String ReceiverSessionID = time + "bookingnetR";
        String rq;
        String rs = null;

        try {
            sb.append("<?xml version='1.0' ?>");
            sb.append("<TravelMessage VersionID='1.8N'>");
            sb.append(" <Control Language='NL' Test='nee'>");
            sb.append("    <SenderSessionID>" + SenderSessionID + "</SenderSessionID>");
            sb.append("    <ReceiverSessionID>" + ReceiverSessionID + "</ReceiverSessionID>");
            sb.append("    <Date>" + DF.format(new Date()) + "</Date>");
            sb.append("    <Time Reliability='zeker'>" + TF.format(new Date()) + "</Time>");
            sb.append("   <MessageSequence>1</MessageSequence>");
            sb.append("   <SenderID>" + SENDERID + "</SenderID>");
            sb.append("  <ReceiverID>NPS001</ReceiverID>");
            sb.append("   <RequestID>AvailabilitybookingnetRequest</RequestID>");
            sb.append("   <ResponseID>AvailabilitybookingnetResponse</ResponseID>");
            sb.append(" </Control>");
            sb.append("  <TRequest>");
            sb.append("    <AvailabilitybookingnetRequest>");
            sb.append("      <PackageDetails WaitListCheck='ja'>");
            sb.append("          <AccommodationID>" + "A" + productAltId + "</AccommodationID>");
            sb.append("          <ArrivalDate>" + DF.format(reservation.getFromdate()) + "</ArrivalDate>");
            sb.append("        <Duration DurationType='dagen'>" + reservation.getDuration(Time.DAY).intValue()
                    + "</Duration>");
            sb.append("     </PackageDetails>");
            sb.append("   </AvailabilitybookingnetRequest>");
            sb.append("  </TRequest>");
            sb.append("</TravelMessage>");

            rq = sb.toString();
            rs = getConnection(rq); // fix code have better support. gettting errors when deploying with tomcat.

            LOG.debug("computePrice rq: \n" + rq + "\n");
            LOG.debug("computePrice rs: \n" + rs + "\n");

            XPathFactory factory = XPathFactory.newInstance();
            XPath xpath = factory.newXPath();
            InputSource inputSource = new InputSource(new StringReader(rs.toString()));
            Double price = (Double) xpath.evaluate("//Price", inputSource, XPathConstants.NUMBER);
            if (Double.isNaN(price)) {
                throw new ServiceException(Error.product_not_available);
            }

            price = price / 100.00; //price is a whole number

            factory = XPathFactory.newInstance();
            xpath = factory.newXPath();
            inputSource = new InputSource(new StringReader(rs.toString()));
            String fromCurrency = (String) xpath.evaluate("//Price/@Currency", inputSource, XPathConstants.STRING);
            if ("".equals(fromCurrency)) {
                throw new ServiceException(Error.price_missing, reservation.getId() + " State = "
                        + reservation.getState() + " currency = " + reservation.getCurrency());
            }
            String tocurrency = reservation.getCurrency();
            if (!fromCurrency.equalsIgnoreCase(tocurrency)) {
                // Double rate = OpenExchangeRates.getExchangeRate(currency,rescurrency);
                Double rate = WebService.getRate(sqlSession, fromCurrency, tocurrency, new Date());
                price = rate * price;
            }

            LOG.debug("price = " + price);
            reservation.setPrice(price);
            reservation.setQuote(price);
        } catch (Throwable e) {
            LOG.error(e.getMessage());
            reservation.setPrice(0.00);
        }
        return reservation;
    }

    @Override
    public void readAdditionCosts() {
        // TODO Auto-generated method stub
    }

    @Override
    public void inquireReservation(SqlSession sqlSession, Reservation reservation) {
        throw new ServiceException(Error.service_absent, "Nextpax inquireReservation()");
    }
}