{ config, pkgs, serverInfo
}:

let

  prefix = "/svn";
  dbDir = "/tmp/svn/db";
  reposDir = "/tmp/svn/repos";
  backupsDir = "/tmp/svn/backup";
  distsDir = "/tmp/svn/dist";
  tmpDir = "/tmp/svn/tmp";
  logDir = "/tmp/svn/log";
  adminAddr = "eelco@cs.uu.nl";
  userCreationDomain = "10.0.0.0/8";
  orgUrl = "http://www.cs.uu.nl/";
  orgLogoUrl = "${prefix}/UU_merk.gif";
  orgName = "Utrecht University";
  postCommitHook = "/var/run/current-system/sw/bin/svn-server-post-commit-hook";
  autoVersioning = true;
  notificationSender = "root@buildfarm.st.ewi.tudelft.nl";
  fsType = "fsfs";
  smtpHost = "mail.st.ewi.tudelft.nl";


  # Build a Subversion instance with Apache modules and Swig/Python bindings.
  subversion = import ../../../nixpkgs/pkgs/applications/version-management/subversion-1.4.x {
    inherit (pkgs) fetchurl stdenv apr aprutil neon expat swig zlib;
    bdbSupport = true;
    httpServer = true;
    sslSupport = true;
    compressionSupport = true;
    pythonBindings = true;
    httpd = pkgs.apacheHttpd;
  };


  # Build the maintenance scripts and commit hooks.
  scripts = substituteInAll {
    name = "svn-server-scripts";
    src = pkgs.lib.cleanSource ../../../services/subversion/src/scripts;

    # The variables to substitute:
    
    inherit reposDir dbDir logDir distsDir backupsDir tmpDir
      adminAddr notificationSender userCreationDomain fsType
      subversion orgUrl orgLogoUrl orgName smtpHost
      postCommitHook;
      
    perl = "${pkgs.perl}/bin/perl";

    sendmail = "${pkgs.ssmtp}/sbin/sendmail";
    
    urlPrefix = prefix;
    
    inherit (pkgs) libxslt enscript db4 coreutils bzip2;

    inherit (serverInfo) canonicalName;
    
    # Urgh, most of these are dependencies of Email::Send, should figure them out automatically.
    perlFlags = map (x: "-I${x}/lib/site_perl") [
      pkgs.perlBerkeleyDB pkgs.perlEmailSend pkgs.perlEmailSimple
      pkgs.perlModulePluggable pkgs.perlReturnValue pkgs.perlEmailAddress
      pkgs.perlCryptPasswordMD5 pkgs.perlStringMkPasswd
    ];

    # Do a syntax check on the generated file.
    postInstall = ''
      $perl -c -T $out/cgi-bin/repoman.pl; $perl -c $out/bin/svn-server-create-user.pl
    '';
  };

  
  # Build our custom authentication modules.
  authModules = import ../../../services/subversion/src/auth {
    inherit (pkgs) stdenv apacheHttpd;
  };


  commonAuth = ''
    AuthType Basic
    AuthName "Subversion repositories"
    AuthBasicProvider auth-against-db
  '';
  

  # Access controls for /repos and /repos-xml. 
  reposConfig = dirName: ''
    ${commonAuth}

    AuthAllowNone on

    AuthzRepoPrefix ${prefix}/${dirName}/
    AuthzRepoDBType DB
    AuthzRepoReaders ${dbDir}/svn-readers
    AuthzRepoWriters ${dbDir}/svn-writers

    <LimitExcept GET PROPFIND OPTIONS REPORT>
        Require repo-writer
    </LimitExcept>

    <Limit GET PROPFIND OPTIONS REPORT>
        Require repo-reader
    </Limit>

    DAV svn
    SVNParentPath ${reposDir}
    SVNAutoversioning ${if autoVersioning then "on" else "off"}
  '';


  # Build ViewVC.
  viewvc = import ../../../services/subversion/src/viewvc {
    inherit (pkgs) fetchurl stdenv python enscript;
    inherit reposDir adminAddr subversion;
    urlPrefix = prefix;
  };


  viewerConfig = dirName: ''
    ${commonAuth}
    AuthAllowNone on
    AuthzRepoPrefix ${prefix}/${dirName}/
    AuthzRepoDBType DB
    AuthzRepoReaders ${dbDir}/svn-readers
    Require repo-reader
  '';


  viewvcConfig = ''
    ScriptAlias ${prefix}/viewvc ${viewvc}/viewvc/bin/mod_python/viewvc.py

    <Location ${prefix}/viewvc>
        AddHandler python-program .py
        # Note: we write \" instead of ' to work around a lexer bug in Nix 0.11.
        PythonPath "[\"${viewvc}/viewvc/bin/mod_python\", \"${subversion}/lib/python2.4/site-packages\"] + sys.path"
        PythonHandler handler
        ${viewerConfig "viewvc"}
    </Location>

    Alias ${prefix}/viewvc-doc ${viewvc}/viewvc/templates/docroot

    Redirect permanent ${prefix}/viewcvs ${serverInfo.canonicalName}/${prefix}/viewvc
  '';


  # Build WebSVN.
  websvn = import ../../../services/subversion/src/websvn {
    inherit (pkgs) fetchurl stdenv writeText enscript gnused diffutils;
    inherit reposDir subversion;
    cacheDir = tmpDir;
    urlPrefix = prefix;
  };

  
  websvnConfig = ''
    Alias ${prefix}/websvn ${websvn}/wsvn.php
    Alias ${prefix}/templates ${websvn}/templates

    <Location ${prefix}/websvn>
        ${viewerConfig "websvn"}
    </Location>

    <Directory ${websvn}/templates>
        Order allow,deny
        Allow from all
    </Directory>
  '';


  distConfig = ''
    Alias ${prefix}/dist ${distsDir}

    <Directory "${distsDir}">
        AllowOverride None
        Options Indexes FollowSymLinks
        Order allow,deny
        Allow from all
        IndexOptions +SuppressDescription +NameWidth=*
        IndexIgnore *.rev *.lock
        IndexStyleSheet ${prefix}/style.css
    </Directory>

    <Location ${prefix}/dist>
        ${viewerConfig "dist"}
    </Location>
  '';
  

  repomanConfig = ''
    ScriptAlias ${prefix}/repoman ${scripts}/cgi-bin/repoman.pl

    <Location ${prefix}/repoman/listdetails>
        ${commonAuth}    
        Require valid-user
    </Location>

    <Location ${prefix}/repoman/adduser>
        Order deny,allow
        Deny from all
        Allow from 127.0.0.1
        Allow from ${userCreationDomain}
    </Location>

    <Location ${prefix}/repoman/edituser>
        ${commonAuth}    
        Require valid-user
    </Location>

    <Location ${prefix}/repoman/create>
        ${commonAuth}    
        Require valid-user
        Order deny,allow
        Deny from all
        Allow from 127.0.0.1
        Allow from ${userCreationDomain}
    </Location>

    <Location ${prefix}/repoman/update>
        ${commonAuth}    
        Require valid-user
    </Location>

    <Location ${prefix}/repoman/dump>
        ${viewerConfig "repoman/dump"}
    </Location>
  '';


  staticFiles = substituteInSome {
    name = "svn-static-files";
    src = pkgs.lib.cleanSource ../../../services/subversion/root;
    urlPrefix = prefix;
    files = ["xsl/svnindex.xsl"];
  };

  staticFilesConfig = ''
    Alias ${prefix} ${staticFiles}
    <Directory ${staticFiles}>
        Order allow,deny
        Allow from all
        AllowOverride None
        DirectoryIndex repoman
    </Directory>
  '';

  
  # !!! should be in Nixpkgs.
  writeTextInDir = name: text:
    pkgs.runCommand name {inherit text;} ''ensureDir $out; echo -n "$text" > $out/$name'';

  substituteInSome = args: pkgs.stdenvUsingSetupNew2.mkDerivation ({
    buildCommand = ''
      ensureDir $out
      cp -prd $src/* $out
      chmod -R u+w $out
      for i in $files; do
        substituteAll $out/$i $out/$i
      done
    '';
  } // args); # */
    
  substituteInAll = args: pkgs.stdenvUsingSetupNew2.mkDerivation ({
    buildCommand = ''
      ensureDir $out
      cp -prd $src/* $out
      chmod -R u+w $out
      find $out -type f -print | while read fn; do
        substituteAll $fn $fn
      done
      eval "$postInstall"
    '';
  } // args); # */
    
in

{

  extraModulesPre = [
    # Allow anonymous access to repositories that are world-readable
    # without prompting for a username/password.
    { name = "authn_noauth"; path = "${authModules}/modules/mod_authn_noauth.so"; }
    # Check whether the user is allowed read or write access to a
    # repository.
    { name = "authz_dyn";    path = "${authModules}/modules/mod_authz_dyn.so"; }
  ];

  extraModules = [
    { name = "python";  path = "${pkgs.mod_python}/modules/mod_python.so"; }
    { name = "php5";    path = "${pkgs.php}/modules/libphp5.so"; }
    { name = "dav_svn"; path = "${subversion}/modules/mod_dav_svn.so"; }
  ];

  extraConfig = ''

    #RedirectPermanent ^${prefix}$ ${prefix}/repoman
  
    <AuthnProviderAlias dbm auth-against-db>
        AuthDBMType DB
        AuthDBMUserFile ${dbDir}/svn-users
    </AuthnProviderAlias>

    <Location ${prefix}/repos>
      ${reposConfig "repos"}
    </Location>
    
    <Location ${prefix}/repos-xml>
      ${reposConfig "repos-xml"}
      SVNIndexXSLT "${prefix}/xsl/svnindex.xsl"
    </Location>

    ${viewvcConfig}

    ${websvnConfig}

    ${repomanConfig}

    ${distConfig}

    ${staticFilesConfig}
        
  '';

  robotsEntries = ''
    User-agent: *
    Disallow: ${prefix}/viewcvs/
    Disallow: ${prefix}/viewvc/
    Disallow: ${prefix}/websvn/
    Disallow: ${prefix}/repos-xml/
  '';

  # mod_python's own Python modules must be in the initial Python
  # path, they cannot be set through the PythonPath directive.
  globalEnvVars = [
    { name = "PYTHONPATH"; value = "${pkgs.mod_python}/lib/python2.4/site-packages"; }
  ];

  extraServerPath = [
    # Needed for ViewVC.
    "${pkgs.diffutils}/bin"
    "${pkgs.gnused}/bin"
  ];

  extraPath = [scripts];
  
}