#!/usr/bin/env python
# PatScanUI - Search for patterns in genomic data
# Copyright (C) 2012  Kai Blin <kai.blin@biotech.uni-tuebingen.de>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import uuid
import subprocess
from os import path, listdir, utime
from flask import Flask, render_template, request, jsonify
from flask import send_from_directory
from helperlibs.wrappers.io import TemporaryPipe

app = Flask(__name__)
app.secret_key = "secret"
app.config['UPLOAD_FOLDER'] = '/memdisk/store'
app.config['PROVIDED_FOLDER'] = '/data/genomes/fasta'

ALLOWED_EXTENSIONS = set(['fa', 'fna', 'fasta', 'faa', 'txt'])

@app.route('/')
def index():
    return render_template('index.html')

def _is_available(filename, provided=False):
    if provided:
        udir = app.config['PROVIDED_FOLDER']
    else:
        udir = app.config['UPLOAD_FOLDER']
    filelist = [fn for fn in listdir(udir) if path.isfile(path.join(udir,fn))]
    return filename in filelist

@app.route('/available')
def available():
    udir = app.config['PROVIDED_FOLDER']
    filelist = [fn for fn in listdir(udir) if path.isfile(path.join(udir,fn))]
    filelist.sort()
    return jsonify(available_files=filelist)

@app.route('/check/<filename>')
def check(filename):
    available = _is_available(filename)
    return jsonify(available=available)

def allowed_filename(name):
    return '.' in name and name.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS

@app.route('/upload', methods=['POST'])
def upload():
    new_file = request.files['file']
    if new_file and allowed_filename(new_file.filename):
        filename = "%s.fa" % uuid.uuid4()
        new_file.save(path.join(app.config['UPLOAD_FOLDER'], filename))
        return jsonify(result="ok", filename=filename)
    return jsonify(result="error", message="invalid filename")


def _update_timestamp(filename):
    udir = app.config['UPLOAD_FOLDER']
    utime(path.join(udir, filename), None)


def _run_patscan(filename, provided, pattern, molecule_type):
    try:
        if provided:
            full_path = path.join(app.config['PROVIDED_FOLDER'], filename)
        else:
            full_path = path.join(app.config['UPLOAD_FOLDER'], filename)
        with open(full_path, 'r') as handle:
            with TemporaryPipe() as pipe:
                command_line = ['patscan', '-c']
                if molecule_type.lower() == "protein":
                    command_line.append('-p')
                command_line.append(pipe)
                p1 = subprocess.Popen(command_line, stdin=handle, stdout=subprocess.PIPE)
                with open(pipe, 'w') as w:
                    w.write(pattern)
                p2 = subprocess.Popen(['patscan_show_hits'], stdin=p1.stdout, stdout=subprocess.PIPE)
                p1.stdout.close()
                result, error = p2.communicate()
    except IOError as e:
        result = "Running patscan failed: %r" % e
    except OSError as e:
        result = "Running patscan failed: %r" % e

    return result


@app.route('/analyze', methods=['post'])
def analyze():
    pattern = request.form.get('pattern', None)
    filename = request.form.get('filename', None)
    molecule_type = request.form.get('molecule', 'DNA')
    provided = True if request.form.get('provided', "false") == "true" else False

    if filename is None or not _is_available(filename, provided):
        return "session expired"

    if pattern is None:
        return "No pattern given"

    if not provided:
        _update_timestamp(filename)

    result = _run_patscan(filename, provided, pattern, molecule_type)

    return result


@app.route('/favicon.ico')
def favicon():
    return send_from_directory(path.join(app.root_path, 'static'),
                               'favicon.ico',
                               mimetype="image/vnd.microsoft.icon")

if __name__ == '__main__':
    app.run(debug=True)

@@ -790,16 +790,26 @@
 ses/%3E.%0A%0A
+import os%0A
 import u
@@ -812,16 +812,16 @@
 rt uuid%0A
-
 import s
@@ -830,16 +830,46 @@
 process%0A
+import tempfile%0Aimport shutil%0A
 from os 
@@ -996,57 +996,8 @@
 tory
-%0Afrom helperlibs.wrappers.io import TemporaryPipe
 %0A%0Aap
@@ -1078,16 +1078,8 @@
 = '/
-memdisk/
 stor
@@ -1136,16 +1136,16 @@
 fasta'%0A%0A
-
 ALLOWED_
@@ -1200,16 +1200,457 @@
 txt'%5D)%0A%0A
+%0Aclass TemporaryPipe(object):%0A    def __init__(self, pipename=%22pipe%22):%0A        self.pipename = pipename%0A        self.tempdir = None%0A%0A    def __enter__(self):%0A        self.tempdir = tempfile.mkdtemp()%0A        pipe_path = path.join(self.tempdir, self.pipename)%0A        os.mkfifo(pipe_path)%0A        return pipe_path%0A%0A    def __exit__(self, type, value, traceback):%0A        if self.tempdir is not None:%0A            shutil.rmtree(self.tempdir)%0A%0A%0A
 @app.rou
@@ -4879,10 +4879,37 @@
 bug=True
+, host='0.0.0.0', port=8000
 )%0A

Make PatScanUI ready for containers