/*
 * $Id: UserListForm.java,v 1.38 2007/08/09 14:38:53 marbobo Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 *
 * $Log: UserListForm.java,v $
 * Revision 1.38  2007/08/09 14:38:53  marbobo
 * - 2 falsch zugeordnete LDAP- Parameter entfernt
 * + Löschen und Aktivieren von Lizenzen hinzugefügt
 *
 * Revision 1.37  2007/05/29 08:01:26  korowa
 * Bugfixing: Benutzerverwaltung jetzt auch für alle mögliche arten fon Administratoren erlaubt
 *
 * Revision 1.36  2007/02/01 14:32:21  korowa
 * Zwei Felder zu SystemParameter hinzugefügt die einem Administrator erlauben das Anlegen von neuen Benutzer oder das Ändern der Passwörter zu regeln.
 *
 * Revision 1.35  2006/05/28 18:10:54  marbobo
 * + Benutzer- und Gruppensuche nach Umlauten nochmals verbessert
 *
 * Revision 1.34  2006/04/29 18:39:47  marbobo
 * + Refactoriengs und eine Ausgaben vereinheitlicht
 *
 * Revision 1.33  2006/02/27 16:16:19  marbobo
 * + Systemsichten hinzugefügt
 * + SysLinks angepasst
 * + Benutzer können falls gewünscht Dokumentqueries anlegen
 *
 * Revision 1.32  2005/09/15 23:16:42  marbobo
 * + Sprachabhängiges Sortieren implementiert
 *
 * Revision 1.31  2005/02/20 16:57:26  marbobo
 * + Beim Speichern der Entities in die Datenbank wird sichergestellt
 *    dass Unicode-Zeichen in Kodierterform (als &#xxxxx;) gespeichert werden
 *
 * Revision 1.30  2005/02/16 23:00:31  marbobo
 * + Suche auf Unicode-Zeichen erweitert
 *
 * Revision 1.29  2005/02/15 09:26:53  bigmac
 * Refactorings
 *
 * Revision 1.28  2005/02/08 16:15:45  bigmac
 * Spalte Quota und #Dok entfernt
 *
 * Revision 1.27  2005/01/20 11:20:08  bigmac
 * getHelpText() entfernt
 *
 * Revision 1.26  2004/11/14 21:37:18  marbobo
 * + getHelpText()
 *
 * Revision 1.25  2004/11/13 20:43:59  marbobo
 * + Bugfix bei der Benutzersuche ( Betrifft die Literal Behandlung )
 *
 * Revision 1.24  2004/11/12 18:45:19  marbobo
 * + Bugfix
 *
 * Revision 1.23  2004/11/12 00:26:11  marbobo
 * + Suche nach Benutzern vervollständigt
 *
 * Revision 1.22  2004/11/11 14:16:23  marbobo
 * + Suche nach Benutzern implementiert ( Joker verwendung  % = * , _ = ? )
 *
 * Revision 1.21  2004/09/16 11:38:19  marbobo
 * added copyright info + cvs log
 *
 */

package vkc.administration.form;

import java.text.CollationKey;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts.action.ActionMapping;

import vkc.db.serializer.VKCSysParameterSerializer;
import vkc.db.serializer.VKCUserSerializer;
import vkc.exception.DBException;
import vkc.util.StringUtils;
import vkc.util.VKCStringUtils;
import vkc.view.bean.UserInfo;
import vkc.view.bean.UserInfoRange;
import vkc.view.form.BasicActionForm;

public final class UserListForm extends BasicActionForm {
    public final static int SORT_USERNAME_UP    		= 1;
    public final static int SORT_USERNAME_DOWN  		= 2;

    public final static int SORT_FIRSTNAME_UP   		= 3;
    public final static int SORT_FIRSTNAME_DOWN 		= 4;

    public final static int SORT_LASTNAME_UP    		= 5;
    public final static int SORT_LASTNAME_DOWN  		= 6;

    public final static int SORT_ACCOUNTSTATUS_UP   	= 7;
    public final static int SORT_ACCOUNTSTATUS_DOWN 	= 8;

    public final static int SORT_PWDCHANGED_UP    		= 11;
    public final static int SORT_PWDCHANGED_DOWN  		= 12;

    public final static int SORT_CREATOR_UP  			= 15;
    public final static int SORT_CREATOR_DOWN 			= 16;

    public final static int SORT_CREATED_UP  			= 17;
    public final static int SORT_CREATED_DOWN 			= 18;

    public final static int SORT_LASTLOGIN_UP  			= 19;
    public final static int SORT_LASTLOGIN_DOWN 		= 20;

	private HashMap ranges	= new HashMap();

    private Integer allUsersCount	= new Integer(0);
    private Integer listIndex    	= new Integer(0);
    private Integer sortMode     	= new Integer(SORT_USERNAME_UP);
    private Integer usersPerPage	= new Integer(10);

    private Integer[] selectedIds	= new Integer[0];

    private String searchQuery 			= "";
    private String selectedCmdAction	= "noaction";

    private UserInfo[] userInfos	= null;

    public void reset(ActionMapping mapping, HttpServletRequest request) {
        super.reset(mapping, request);

        userInfos = null;
        sortMode = new Integer(SORT_USERNAME_UP);
        selectedCmdAction = "noaction";
    }

    public UserInfo[] getUserInfos() throws DBException {
        if (userInfos == null) {
            userInfos = new UserInfo[0];
            setAllUsersCount(new Integer(0));

            if (getUser().hasAdminPrivileges()) {
                setAllUsersCount(new Integer(VKCUserSerializer.getAllUsersCount()));

                if (getAllUsersCount().intValue() > 0) {
                    if (!isEmpty(getSearchQuery())) {
                    	String[] xqueries = getDatabaseXmlEntityQueries();
                    	String[] queries = new String[1 + xqueries.length];
                    	queries[0] = getDatabaseQuery();
                    	
                    	for (int i = 0; i < xqueries.length; i++) {
							queries[i + 1] = xqueries[i];
						}
                    	
                        userInfos = (UserInfo[])VKCUserSerializer.retrieveUserInfosByQueries(queries).toArray(new UserInfo[0]);
                    } else {
                        userInfos = (UserInfo[])VKCUserSerializer.retrieveUserInfos().toArray(new UserInfo[0]);
                    }
                }
            } else if (getUser().isDedicatedUsersAdmin()) {
                setAllUsersCount(new Integer(VKCUserSerializer.getAllUsersCountByCreator(getUser().getUserId())));

                if (getAllUsersCount().intValue() > 0) {
                    if (!isEmpty(getSearchQuery())) {
                    	String[] xqueries = getDatabaseXmlEntityQueries();
                    	String[] queries = new String[1 + xqueries.length];
                    	queries[0] = getDatabaseQuery();
                    	
                    	for (int i = 0; i < xqueries.length; i++) {
							queries[i + 1] = xqueries[i];
						}
                    	
                        userInfos = (UserInfo[])VKCUserSerializer.retrieveUserInfosByCreatorAndQueries(getUser().getUserId(), queries).toArray(new UserInfo[0]);
                    } else {
                        userInfos = (UserInfo[])VKCUserSerializer.retrieveUserInfosByCreator(getUser().getUserId()).toArray(new UserInfo[0]);
                    }
                }
            }

            sort(userInfos, getSortMode());
        }

        return userInfos;
    }

    public void sort(UserInfo[] userInfos, Integer sortMode) throws DBException {
        int mode = sortMode.intValue();

        Comparator c = null;
		final Collator collator = Collator.getInstance(getUser().getLanguage().getLocale());

        if (mode == SORT_USERNAME_UP) {
            c = new Comparator() {
                public int compare(Object o1, Object o2) {
                    UserInfo u1 = (UserInfo)o1;
                    UserInfo u2 = (UserInfo)o2;

                	CollationKey key1 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u1.getUsername()));
                	CollationKey key2 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u2.getUsername()));
                	
                	return key1.compareTo(key2);
                }
            };
        } else if (mode == SORT_USERNAME_DOWN) {
            c = new Comparator() {
                public int compare(Object o1, Object o2) {
                    UserInfo u1 = (UserInfo)o1;
                    UserInfo u2 = (UserInfo)o2;

                	CollationKey key1 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u1.getUsername()));
                	CollationKey key2 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u2.getUsername()));
                	
                	return key2.compareTo(key1);
                }
            };
        } else if (mode == SORT_FIRSTNAME_UP) {
            c = new Comparator() {
                public int compare(Object o1, Object o2) {
                    UserInfo u1 = (UserInfo)o1;
                    UserInfo u2 = (UserInfo)o2;

                	CollationKey key1 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u1.getFirstname()));
                	CollationKey key2 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u2.getFirstname()));
                	
                	return key1.compareTo(key2);
                }
            };
        } else if (mode == SORT_FIRSTNAME_DOWN) {
            c = new Comparator() {
                public int compare(Object o1, Object o2) {
                    UserInfo u1 = (UserInfo)o1;
                    UserInfo u2 = (UserInfo)o2;

                	CollationKey key1 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u1.getFirstname()));
                	CollationKey key2 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u2.getFirstname()));
                	
                	return key2.compareTo(key1);
                }
            };
        } else if (mode == SORT_LASTNAME_UP) {
            c = new Comparator() {
                public int compare(Object o1, Object o2) {
                    UserInfo u1 = (UserInfo)o1;
                    UserInfo u2 = (UserInfo)o2;

                	CollationKey key1 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u1.getLastname()));
                	CollationKey key2 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u2.getLastname()));
                	
                	return key1.compareTo(key2);
                }
            };
        } else if (mode == SORT_LASTNAME_DOWN) {
            c = new Comparator() {
                public int compare(Object o1, Object o2) {
                    UserInfo u1 = (UserInfo)o1;
                    UserInfo u2 = (UserInfo)o2;

                	CollationKey key1 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u1.getLastname()));
                	CollationKey key2 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u2.getLastname()));
                	
                	return key2.compareTo(key1);
                }
            };
        } else if (mode == SORT_CREATOR_UP) {
            final HashMap users = getAllUserInfos();
            c = new Comparator() {
                public int compare(Object o1, Object o2) {
                    UserInfo u1 = (UserInfo)o1;
                    UserInfo u2 = (UserInfo)o2;
                    String k1 = u1.getCreatorId() == null ? "" : u1.getCreatorId().toString();
                    String k2 = u2.getCreatorId() == null ? "" : u2.getCreatorId().toString();
                    UserInfo c1 = (UserInfo)users.get(k1);
                    UserInfo c2 = (UserInfo)users.get(k2);

                    if (c1 == null && c2 == null) {
                    	CollationKey key1 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u1.getUsername()));
                    	CollationKey key2 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u2.getUsername()));
                    	
                    	return key1.compareTo(key2);
                    }

                    if (c1 == null) {
                        return -1;
                    }

                    if (c2 == null) {
                        return 1;
                    }

                	CollationKey key1 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(c1.getUsername()));
                	CollationKey key2 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(c2.getUsername()));
                	
                	return key1.compareTo(key2);
                }
            };
        } else if (mode == SORT_CREATOR_DOWN) {
            final HashMap users = getAllUserInfos();
            c = new Comparator() {
                public int compare(Object o1, Object o2) {
                    UserInfo u1 = (UserInfo)o1;
                    UserInfo u2 = (UserInfo)o2;
                    String k1 = u1.getCreatorId() == null ? "" : u1.getCreatorId().toString();
                    String k2 = u2.getCreatorId() == null ? "" : u2.getCreatorId().toString();
                    UserInfo c1 = (UserInfo)users.get(k1);
                    UserInfo c2 = (UserInfo)users.get(k2);

                    if (c1 == null && c2 == null) {
                    	CollationKey key1 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u1.getUsername()));
                    	CollationKey key2 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u2.getUsername()));
                    	
                    	return key2.compareTo(key1);
                    }

                    if (c1 == null) {
                        return 1;
                    }

                    if (c2 == null) {
                        return -1;
                    }

                	CollationKey key1 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(c1.getUsername()));
                	CollationKey key2 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(c2.getUsername()));
                	
                	return key2.compareTo(key1);
                }
            };
        } else if (mode == SORT_CREATED_UP) {
            c = new Comparator() {
                public int compare(Object o1, Object o2) {
                    UserInfo u1 = (UserInfo)o1;
                    UserInfo u2 = (UserInfo)o2;

                    if (u1.getCreated() == null && u2.getCreated() == null) {
                    	CollationKey key1 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u1.getUsername()));
                    	CollationKey key2 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u2.getUsername()));
                    	
                    	return key1.compareTo(key2);
                    }

                    if (u1.getCreated() == null) {
                        return -1;
                    }

                    if (u2.getCreated() == null) {
                        return 1;
                    }

                    return u1.getCreated().after(u2.getCreated()) ? 1 : 0;
                }
            };
        } else if (mode == SORT_CREATED_DOWN) {
            c = new Comparator() {
                public int compare(Object o1, Object o2) {
                    UserInfo u1 = (UserInfo)o1;
                    UserInfo u2 = (UserInfo)o2;

                    if (u1.getCreated() == null && u2.getCreated() == null) {
                    	CollationKey key1 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u1.getUsername()));
                    	CollationKey key2 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u2.getUsername()));
                    	
                    	return key2.compareTo(key1);
                    }

                    if (u1.getCreated() == null) {
                        return 1;
                    }

                    if (u2.getCreated() == null) {
                        return -1;
                    }

                    return u1.getCreated().before(u2.getCreated()) ? 1 : 0;
                }
            };
        } else if (mode == SORT_LASTLOGIN_UP) {
            c = new Comparator() {
                public int compare(Object o1, Object o2) {
                    UserInfo u1 = (UserInfo)o1;
                    UserInfo u2 = (UserInfo)o2;

                    if (u1.getMostRecentLogin() == null && u2.getMostRecentLogin() == null) {
                    	CollationKey key1 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u1.getUsername()));
                    	CollationKey key2 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u2.getUsername()));
                    	
                    	return key1.compareTo(key2);
                    }

                    if (u1.getMostRecentLogin() == null) {
                        return -1;
                    }

                    if (u2.getMostRecentLogin() == null) {
                        return 1;
                    }

                    return u1.getMostRecentLogin().after(u2.getMostRecentLogin()) ? 1 : 0;
                }
            };
        } else if (mode == SORT_LASTLOGIN_DOWN) {
            c = new Comparator() {
                public int compare(Object o1, Object o2) {
                    UserInfo u1 = (UserInfo)o1;
                    UserInfo u2 = (UserInfo)o2;

                    if (u1.getMostRecentLogin() == null && u2.getMostRecentLogin() == null) {
                    	CollationKey key1 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u1.getUsername()));
                    	CollationKey key2 = collator.getCollationKey(VKCStringUtils.decodeXmlEntities(u2.getUsername()));
                    	
                    	return key2.compareTo(key1);
                    }

                    if (u1.getMostRecentLogin() == null) {
                        return 1;
                    }

                    if (u2.getMostRecentLogin() == null) {
                        return -1;
                    }

                    return u1.getMostRecentLogin().before(u2.getMostRecentLogin()) ? 1 : 0;
                }
            };
        } else if (mode == SORT_ACCOUNTSTATUS_UP) {
            c = new Comparator() {
                public int compare(Object o1, Object o2) {
                    UserInfo u1 = (UserInfo)o1;
                    UserInfo u2 = (UserInfo)o2;
                    int u1Value = u1.isUserValid() ? 1 : 0;
                    int u2Value = u2.isUserValid() ? 1 : 0;

                    return u1Value > u2Value ? 1 : 0;
                }
            };
        } else if (mode == SORT_ACCOUNTSTATUS_DOWN) {
            c = new Comparator() {
                public int compare(Object o1, Object o2) {
                    UserInfo u1 = (UserInfo)o1;
                    UserInfo u2 = (UserInfo)o2;
                    int u1Value = u1.isUserValid() ? 1 : 0;
                    int u2Value = u2.isUserValid() ? 1 : 0;

                    return u1Value < u2Value ? 1 : 0;
                }
            };
        } else if (mode == SORT_PWDCHANGED_DOWN) {
            c = new Comparator() {
                public int compare(Object o1, Object o2) {
                    UserInfo u1 = (UserInfo)o1;
                    UserInfo u2 = (UserInfo)o2;
                    int u1Value = u1.isPwdChanged() ? 1 : 0;
                    int u2Value = u2.isPwdChanged() ? 1 : 0;

                    return u1Value < u2Value ? 1 : 0;
                }
            };
        } else if (mode == SORT_PWDCHANGED_UP) {
            c = new Comparator() {
                public int compare(Object o1, Object o2) {
                    UserInfo u1 = (UserInfo)o1;
                    UserInfo u2 = (UserInfo)o2;
                    int u1Value = u1.isPwdChanged() ? 1 : 0;
                    int u2Value = u2.isPwdChanged() ? 1 : 0;

                    return u1Value > u2Value ? 1 : 0;
                }
            };
		}

        Arrays.sort(userInfos, c);
    }

    private HashMap getAllUserInfos() throws DBException {
        HashMap users = new HashMap();
        List userInfos = VKCUserSerializer.retrieveUserInfos();

        for (int i = 0; i < userInfos.size(); i++) {
            UserInfo u = (UserInfo)userInfos.get(i);
            users.put(u.getUserId().toString(), u);
        }

        return users;
    }

    public void setUserInfos(UserInfo[] infos) {
        userInfos = infos;
    }

    public Integer getAllUsersCount() {
        return allUsersCount;
    }

    public void setAllUsersCount(Integer i) {
        allUsersCount = i;
    }

    public Integer getSortMode() {
        return sortMode;
    }

    public void setSortMode(Integer i) {
        sortMode = i;
    }

    public Integer getUsersPerPage() {
        return usersPerPage;
    }

    public void setUsersPerPage(Integer i) {
        usersPerPage = i;
    }

    public Integer getNumberOfUserInfos() throws DBException {
        return new Integer(getUserInfos().length);
    }

    public Integer getUserInfoPageCount() throws DBException {
        double pageCount = getUserInfos().length;
        pageCount = pageCount / getUsersPerPage().intValue();
        pageCount = Math.ceil(pageCount);

        return new Integer((int)pageCount);
    }

    public Integer[] getPageIndices() throws DBException {
        ArrayList list = new ArrayList();
        ranges.clear();

        for (int i = 0; i < getUserInfoPageCount().intValue(); i++) {
            Integer index = new Integer(i * getUsersPerPage().intValue());
            ranges.put(index, getVisibleUserInfoRanges(index));
            list.add(index);
        }

        return (Integer[])list.toArray(new Integer[list.size()]);
    }

    public Integer getListIndex() {
        return listIndex;
    }

    public void setListIndex(Integer i) {
        listIndex = i;
    }

    public Integer[] getSelectedIds() {
        return selectedIds;
    }

    public void setSelectedIds(Integer[] integers) {
        if (integers == null) {
            selectedIds = new Integer[0];
        } else {
            selectedIds = integers;
        }
    }

    public UserInfo[] getVisibleUserInfos() throws DBException {
        int length = getUsersPerPage().intValue();

        if (getListIndex().intValue() + getUsersPerPage().intValue() > getUserInfos().length) {
            length = getUserInfos().length % getUsersPerPage().intValue();
        }

        UserInfo[] visibleUserInfos = new UserInfo[length];

        if (getUserInfos().length > 0) {
            int sourcepos = getListIndex().intValue();

            if (sourcepos > getUserInfos().length) {
                sourcepos = 0;
                setListIndex(new Integer(0));
            }

            System.arraycopy(getUserInfos(), sourcepos, visibleUserInfos, 0, length);
        }

        return visibleUserInfos;
    }

    public Integer getVisibleUserInfoSizes() throws DBException {
        return new Integer(getVisibleUserInfos().length);
    }

    public UserInfoRange getVisibleUserInfoRanges(Integer pageIndex) throws DBException {
        int fromIndex = pageIndex.intValue();
        int toIndex = fromIndex + (getUsersPerPage().intValue() - 1);
        UserInfo[] userInfos = getUserInfos();
        int endIndex = (userInfos.length % getUsersPerPage().intValue()) - 1;

        if (toIndex >= userInfos.length) {
            toIndex = fromIndex + endIndex;
        }

        UserInfo fromUser = userInfos[fromIndex];
        UserInfo toUser = userInfos[toIndex];

        return new UserInfoRange(fromUser, toUser);
    }

    public Object getRangeValue(String key) {
        return ranges.get(Integer.valueOf(key));
    }

    public String getSelectedCmdAction() {
        return selectedCmdAction;
    }

    public void setSelectedCmdAction(String s) {
        selectedCmdAction = StringUtils.normalize(s);
    }

    public String getSearchQuery() {
        return searchQuery;
    }

    public void setSearchQuery(String s) {
        searchQuery = StringUtils.normalize(s);
    }

    private String getDatabaseQuery() {
        if (isEmpty(getSearchQuery())) {
            return "";
        }

        String query = VKCStringUtils.filterUnicodeChars(clearAloneEscapeChars(getSearchQuery()));
        query = StringUtils.replaceToken(query, "%", "\\%");
        query = StringUtils.replaceToken(query, "_", "\\_");
        query = replaceLiterals(query, "*", "%");
        query = replaceLiterals(query, "?", "_");
        query = replaceLiterals(query, "\\*", "*");
        query = replaceLiterals(query, "\\?", "?");

        return query;
    }

    private String[] getDatabaseXmlEntityQueries() {
        if (isEmpty(getSearchQuery())) {
            return new String[] {};
        }

        String queries[] = new String[5];
        String query = VKCStringUtils.filterUnicodeChars(clearAloneEscapeChars(getSearchQuery()));
        query = StringUtils.replaceToken(query, "%", "\\%");
        query = StringUtils.replaceToken(query, "_", "\\_");
        query = replaceLiterals(query, "*", "%");
        
        for (int i = 0; i < queries.length; i++) {
            String replacement = "&#";
            
            for (int j = 0; j < i + 1; j++) {
				replacement += "_";
			}
            
            replacement += ";";
        	queries[i] = replaceLiterals(query, "?", replacement);
            queries[i] = replaceLiterals(queries[i], "\\*", "*");
            queries[i] = replaceLiterals(queries[i], "\\?", "?");
            queries[i] = queries[i];
		}

        return queries;
    }

    private String clearAloneEscapeChars(String str) {
        StringBuffer sb = new StringBuffer();
        int index = 0;

        while (true) {
            index = str.indexOf("\\");

            if (index < 0) {
                break;
            }

            if (str.startsWith("*", index + 1) || str.startsWith("?", index + 1) || str.startsWith("\\", index + 1)) {
                sb.append(str.substring(0, index + 2));
                str = str.substring(index + 2);
            } else {
                sb.append(str.substring(0, index));
                str = str.substring(index + 1);
            }
        }

        return sb.toString() + str;
    }

    private String replaceLiterals(String str, String literal, String replacement) {
        StringBuffer sb = new StringBuffer();
        int index = 0;

        while (true) {
            index = str.indexOf(literal);

            if (index < 0) {
                break;
            }

            int escapeCount = 0;

            for (int i = index - 1; i >= 0; i--) {
                if (str.charAt(i) == '\\') {
                    escapeCount++;
                } else {
                    break;
                }
            }

            if (escapeCount % 2 == 1) {
                sb.append(str.substring(0, index + literal.length()));
            } else {
                sb.append(str.substring(0, index));
                sb.append(replacement);
            }

            str = str.substring(index + literal.length());
        }

        return sb.toString() + str;
    }

    public String getDeleteUsersLink() {
        String currentLink = "/userList.do?";
	    currentLink += "action.search.redirect=true";
        currentLink += "&listIndex=" + getListIndex();
        currentLink += "&sortMode=" + getSortMode();
        currentLink += "&usersPerPage=" + getUsersPerPage();
	    currentLink += "&searchQuery=" + VKCStringUtils.base64Encode(getSearchQuery());

        return "/deleteUsers.do?initialize=true&redirect=" + VKCStringUtils.base64Encode(currentLink);
    }

    public String getEditUserLink() {
        String currentLink = "/userList.do?";
	    currentLink += "action.search.redirect=true";
        currentLink += "&listIndex=" + getListIndex();
        currentLink += "&sortMode=" + getSortMode();
        currentLink += "&usersPerPage=" + getUsersPerPage();
	    currentLink += "&searchQuery=" + VKCStringUtils.base64Encode(getSearchQuery());

        return "/editUser.do?initialize=true&redirect=" + VKCStringUtils.base64Encode(currentLink);
    }

    public boolean isQuotaEnabled () {
        return VKCSysParameterSerializer.isQuotaCheckingEnabled();
    }

    public boolean getSortByFirstname() {
        return
            getSortMode().intValue() == UserListForm.SORT_FIRSTNAME_UP ||
            getSortMode().intValue() == UserListForm.SORT_FIRSTNAME_DOWN;
    }

    public boolean getSortByLastname() {
        return
            getSortMode().intValue() == UserListForm.SORT_LASTNAME_UP ||
            getSortMode().intValue() == UserListForm.SORT_LASTNAME_DOWN;
    }

    public boolean getSortByAccountStatus() {
        return
            getSortMode().intValue() == UserListForm.SORT_ACCOUNTSTATUS_DOWN ||
            getSortMode().intValue() == UserListForm.SORT_ACCOUNTSTATUS_UP;
    }

    public boolean getSortByPwd() {
        return
            getSortMode().intValue() == UserListForm.SORT_PWDCHANGED_DOWN ||
            getSortMode().intValue() == UserListForm.SORT_PWDCHANGED_UP;
    }

    public boolean getSortByUsername() {
        return
            getSortMode().intValue() == UserListForm.SORT_USERNAME_DOWN ||
            getSortMode().intValue() == UserListForm.SORT_USERNAME_UP;
    }

    public boolean getSortByCreator() {
        return
            getSortMode().intValue() == UserListForm.SORT_CREATOR_DOWN ||
            getSortMode().intValue() == UserListForm.SORT_CREATOR_UP;
    }

    public boolean getSortByCreated() {
        return
            getSortMode().intValue() == UserListForm.SORT_CREATED_DOWN ||
            getSortMode().intValue() == UserListForm.SORT_CREATED_UP;
    }

    public boolean getSortByLastLogin() {
        return
            getSortMode().intValue() == UserListForm.SORT_LASTLOGIN_DOWN ||
            getSortMode().intValue() == UserListForm.SORT_LASTLOGIN_UP;
    }
}