/*
 * Copyright 2006-2007 Queplix Corp.
 *
 * Licensed under the Queplix Public License, Version 1.1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.queplix.com/solutions/commercial-open-source/queplix-public-license/
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *
 */

package com.queplix.core.modules.web;

import com.queplix.core.utils.StringHelper;
import org.apache.regexp.RE;
import org.apache.regexp.RESyntaxException;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.FileSet;

import java.io.CharArrayWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>Java Script url replacer ANT task</p>
 * <p>Replace original JS urls on compiled urls.</p>
 *
 * @author [ALB] Baranov Andrey
 * @version $Revision: 1.2 $ $Date: 2006/07/05 16:53:30 $
 */

public final class URLReplacer
        extends Task {

    // ----------------------------------------------------- variables

    private String jsgName;
    private String browserType;
    private String scriptDir;
    private String relativeURLs;
    private File scriptDirFile;

    private List fileList;

    // ----------------------------------------------------- public methods

    //
    // Setters.
    //

    public void setJsgname(String s) {
        jsgName = s;
    }

    public void setBrowsertype(String s) {
        browserType = s;
    }

    public void setScriptdir(String s) {
        scriptDir = s;
    }

    public void setRelativeURLs(String s) {
        relativeURLs = s;
    }

    public void addConfiguredFileset(FileSet fileset) {
        DirectoryScanner dirscan = fileset.getDirectoryScanner(
                super.getProject());
        String[] files = dirscan.getIncludedFiles();

        for(int i = 0; i < files.length; i++) {
            fileList.add(new File(dirscan.getBasedir(), files[i]));
        }
    }

    /* (non-Javadoc)
     * @see org.apache.tools.ant.Task#execute()
     */
    public void execute()
            throws BuildException {

        // Init.
        if(jsgName == null) {
            throw new BuildException("JS group name is NULL");
        }
        if(browserType == null) {
            throw new BuildException("Browser type is NULL");
        }
        if(scriptDir == null) {
            throw new BuildException("Script dir is NULL");
        }

        if(relativeURLs == null) {
            relativeURLs = "false";
        }

        scriptDirFile = new File(getProject().getBaseDir(), scriptDir);
        if(!scriptDirFile.exists() || !scriptDirFile.isDirectory()) {
            throw new BuildException(
                    "Bad JS dir: " + scriptDirFile.getAbsolutePath());
        }

        for(int i = 0; i < fileList.size(); i++) {
            File f = (File) fileList.get(i);
            log("Replacing JS URL in file: " + f);
            replace(f);
        }
    }

    /* (non-Javadoc)
     * @see org.apache.tools.ant.Task#init()
     */
    public void init() {
        super.init();
        fileList = new ArrayList();
    }

    /* (non-Javadoc)
     * @see org.apache.tools.ant.ProjectComponent#log(java.lang.String)
     */
    public void log(String s) {
        super.log(s);
    }

    // ----------------------------------------------------- private methods

    // Replace all URLs in file <code>f</code>.

    private void replace(File f) {
        String data = String.valueOf(loadFile(f));
        if(StringHelper.isEmpty(data)) {
            return;
        }

        // .. do replace
        boolean replaced = false;
        try {
            RE re = new RE(
                    "<script[ \n\t]*src=\"([^\"]*)\"[ \n\t]*(/>|>[ \n\t]*</script>)",
                    RE.MATCH_CASEINDEPENDENT | RE.MATCH_MULTILINE);

            int curPos = 0;
            while(re.match(data, curPos)) {
                int startPos = re.getParenStart(0);
                int endPos = re.getParenEnd(0);
                int startScriptPos = re.getParenStart(1);
                int endScriptPos = re.getParenEnd(1);

                String url = data.substring(startScriptPos, endScriptPos);
                log("### Found JS url: " + url);

                // ... check if replaced
                if(url.indexOf(WebHelper.SCRIPT_PROD_CORE) >= 0) {
                    break;
                }

                // .. remove first '/'
                if(url.startsWith("/")) {
                    url = url.substring(1);
                }

                if(relativeURLs.equalsIgnoreCase("true")) {
                    url = WebHelper.getNCJSRelativeURL(jsgName, url);
                } else {
                    url = WebHelper.getNCJSURL(jsgName, url);
                }
                File jsFile = new File(scriptDirFile, url);
                log("### New JS url: " + url);

                String script = "<script src=\"" + url + "\"></script>";

                // ... insert implementation
                File implFile = WebHelper.getImplementation(jsFile,
                        browserType);
                if(implFile.exists() && WebHelper.isJSFile(implFile)) {
                    String implUrl = WebHelper.getImplUrl(url, browserType);
                    script += "\n<script src=\"" + implUrl + "\"></script>";
                }

                data = data.substring(0, startPos) + script + data.substring(
                        endPos + 1);
                curPos = startPos + script.length();
                replaced = true;
            }

        } catch (RESyntaxException ex) {
            throw new BuildException("RE exception: " + ex.getMessage(), ex);
        }

        if(replaced) {
            // .. write replacement
            saveFiles(f, data.toCharArray());
        }
    }

    // Load file <code>f</code>.
    private char[] loadFile(File f) {

        CharArrayWriter caw = new CharArrayWriter();
        FileReader fr = null;
        try {
            fr = new FileReader(f);
            int len;
            char[] buf = new char[1024];
            while((len = fr.read(buf)) > 0) {
                caw.write(buf, 0, len);
            }
            return caw.toCharArray();

        } catch (IOException ex) {
            throw new BuildException("IO exception: " + ex.getMessage(), ex);

        } finally {
            try {
                fr.close();
            } catch (Exception ex) {
            }
            try {
                caw.close();
            } catch (Exception ex) {
            }
        }
    }

    // Save data <code>buf</code> to file <code>f</code>.
    private void saveFiles(File f, char[] buf) {

        FileWriter fw = null;
        try {
            fw = new FileWriter(f);
            fw.write(buf);
            fw.flush();

        } catch (IOException ex) {
            throw new BuildException("IO exception: " + ex.getMessage(), ex);

        } finally {
            try {
                fw.close();
            } catch (Exception ex) {
            }
        }
    }
}
